Skip to content

Commit

Permalink
TESTBOX-394
Browse files Browse the repository at this point in the history
new `test(), xtest(), ftest()` alias for more natuarl testing
  • Loading branch information
lmajano committed Sep 7, 2024
1 parent ac27629 commit a862397
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 16 deletions.
6 changes: 6 additions & 0 deletions system/runners/BaseRunner.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ component {
if ( structKeyExists( getMetadata( arguments.target[ arguments.methodName ] ), "test" ) ) {
return true;
}

// Skip: test, ftest, xtest which are internal methods
if ( reFindNoCase( "^(f|x)?test$", arguments.methodName ) ) {
return false;
}

// All xUnit test methods must start or end with the term, "test".
return ( !!reFindNoCase( "(^test|test$)", arguments.methodName ) );
}
Expand Down
40 changes: 24 additions & 16 deletions system/runners/UnitRunner.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -386,26 +386,28 @@ component
required testResults
){
var suite = {
// ID
"id" : hash( arguments.targetMD.name ),
// suite name
name : (
"name" : (
structKeyExists( arguments.targetMD, "displayName" ) ? arguments.targetMD.displayname : arguments.targetMD.name
),
// async flag
asyncAll : ( structKeyExists( arguments.targetMD, "asyncAll" ) ? arguments.targetMD.asyncAll : false ),
"asyncAll" : ( structKeyExists( arguments.targetMD, "asyncAll" ) ? arguments.targetMD.asyncAll : false ),
// skip suite testing flag
skip : (
"skip" : (
structKeyExists( arguments.targetMD, "skip" ) ? (
len( arguments.targetMD.skip ) ? arguments.targetMD.skip : true
) : false
),
// labels attached to the suite for execution
labels : (
"labels" : (
structKeyExists( arguments.targetMD, "labels" ) ? listToArray( arguments.targetMD.labels ) : []
),
// the specs attached to this suite.
specs : getTestMethods( arguments.target, arguments.testResults ),
// the recursive suites
suites : []
"specs" : getTestMethods( arguments.target, arguments.testResults ),
// nested suites
"suites" : []
};

// skip constraint for suite?
Expand All @@ -423,7 +425,10 @@ component
/**
* Retrieve the testing methods/specs from a given target.
*
* @target.hint The target to get the methods from
* @target The target to get the methods from
* @testResults The test results object
*
* @return An array of method specs
*/
private array function getTestMethods( required any target, required any testResults ){
var mResults = [];
Expand All @@ -433,25 +438,28 @@ component
for ( var thisMethod in methodArray ) {
// only valid functions and test functions allowed
if (
isCustomFunction( arguments.target[ thisMethod ] ) &&
( isCustomFunction( arguments.target[ thisMethod ] ) || isClosure( arguments.target[ thisMethod ] ) )
&&
isValidTestMethod( thisMethod, arguments.target )
) {
// Build the spec data packet
var specMD = getMetadata( arguments.target[ thisMethod ] );
var spec = {
name : specMD.name,
hint : ( structKeyExists( specMD, "hint" ) ? specMD.hint : "" ),
skip : ( structKeyExists( specMD, "skip" ) ? ( len( specMD.skip ) ? specMD.skip : true ) : false ),
labels : ( structKeyExists( specMD, "labels" ) ? listToArray( specMD.labels ) : [] ),
order : ( structKeyExists( specMD, "order" ) ? listToArray( specMD.order ) : index++ ),
expectedException : (
"id" : hash( specMD.name ),
"name" : specMD.name,
"hint" : ( structKeyExists( specMD, "hint" ) ? specMD.hint : "" ),
"skip" : ( structKeyExists( specMD, "skip" ) ? ( len( specMD.skip ) ? specMD.skip : true ) : false ),
"focused" : ( structKeyExists( specMD, "focused" ) ? ( len( specMD.focused ) ? specMD.focused : true ) : false ),
"labels" : ( structKeyExists( specMD, "labels" ) ? listToArray( specMD.labels ) : [] ),
"order" : ( structKeyExists( specMD, "order" ) ? listToArray( specMD.order ) : index++ ),
"expectedException" : (
structKeyExists( specMD, "expectedException" ) ? specMD.expectedException : ""
)
};

// skip constraint?
if ( !isBoolean( spec.skip ) && isCustomFunction( arguments.target[ spec.skip ] ) ) {
spec.skip = invoke( arguments.target, "#spec.skip#" );
spec.skip = invoke( arguments.target, spec.skip );
}

// do we have labels applied?
Expand Down
196 changes: 196 additions & 0 deletions tests/index.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
<cfsetting showDebugOutput="false">
<!--- Executes all tests in the 'specs' folder with simple reporter by default --->
<cfparam name="url.reporter" default="simple">
<cfparam name="url.directory" default="tests.specs">
<cfparam name="url.recurse" default="false" type="boolean">
<cfparam name="url.bundles" default="">
<cfparam name="url.labels" default="">
<cfparam name="url.excludes" default="">
<cfparam name="url.reportpath" default="#expandPath( "/tests/results" )#">
<cfparam name="url.propertiesFilename" default="TEST.properties">
<cfparam name="url.propertiesSummary" default="false" type="boolean">
<cfparam name="url.editor" default="vscode">
<cfparam name="url.bundlesPattern" default="*Spec*.cfc|*Test*.cfc|*Spec*.bx|*Test*.bx">

<cfparam name="url.coverageEnabled" default="false">
<cfparam name="url.coverageSonarQubeXMLOutputPath" default="">
<cfparam name="url.coveragePathToCapture" default="#expandPath( '/testbox/system' )#">
<cfparam name="url.coverageWhitelist" default="">
<cfparam name="url.coverageBlacklist" default="/stubs/**">
<cfparam name="url.coverageBrowserOutputDir" default="#expandPath( '/tests/results/coverageReport' )#">

<cfparam name="url.opt_run" default="false">
<cfscript>
// create reporters
reporters = [ "ANTJunit", "Console", "Codexwiki", "Doc", "Dot", "JSON", "JUnit", "Min", "Raw", "Simple", "Tap", "Text", "XML" ];
ASSETS_DIR = expandPath( "/testbox/system/reports/assets" );
if( url.opt_run ){
// Include the TestBox HTML Runner
include "/testbox/system/runners/HTMLRunner.cfm";
abort;
}
</cfscript>

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta name="generator" content="TestBox v#testbox.getVersion()#">
<title>TestBox Runner</title>

<cfoutput>
<style>#fileRead( '#ASSETS_DIR#/css/main.css' )#</style>
<script>#fileRead( '#ASSETS_DIR#/js/jquery-3.3.1.min.js' )#</script>
<script>#fileRead( '#ASSETS_DIR#/js/popper.min.js' )#</script>
<script>#fileRead( '#ASSETS_DIR#/js/bootstrap.min.js' )#</script>
<script>#fileRead( '#ASSETS_DIR#/js/stupidtable.min.js' )#</script>
</cfoutput>
<script>
$(document).ready(function() {
toggleInputsLinkedCheckbox('propertiesSummary', 'propertiesInputs');
toggleInputsLinkedCheckbox('coverageEnabled', 'coverageInputs');
});
function toggleInputsLinkedCheckbox(checkboxId, inputsDivId) {
$(`#${checkboxId}`).on('change', function(){
if($(this).prop("checked")) {
$(`#${inputsDivId}`).find( "input" ).prop('disabled', false);
$(`#${inputsDivId}`).show();
} else {
$(`#${inputsDivId}`).hide();
$(`#${inputsDivId}`).find( "input" ).prop('disabled', true);
}
}).trigger('change');
}
function runTests() {
console.log($("#runnerForm").serialize());
$("#tb-results")
.html("");
$("#btn-run")
.attr("disabled", "disabled")
.html('Running...')
.css("opacity", "0.5");
$("#tb-results")
.load("index.cfm", $("#runnerForm").serialize(), function(data) {
$("#btn-run").removeAttr("disabled").html('Run').css("opacity", "1");
});
}
function clearResults() {
$("#tb-results").html('');
$("#target").html('');
$("#labels").html('');
}
</script>
</head>
<cfoutput>
<body>
<!--- Title --->
<div id="tb-runner" class="container">
<div class="row">
<div class="col-md-4 text-center mx-auto">
<img class="mt-3" src="https://www.ortussolutions.com/__media/testbox-185.png" alt="TestBox" id="tb-logo" />
</div>
</div>
<div class="row">
<div class="col-md-12">
<form name="runnerForm" id="runnerForm">
<input type="hidden" name="opt_run" id="opt_run" value="true" />
<input type="hidden" name="fullPage" id="fullPage" value="false" />
<h2>TestBox Global Runner</h2>
<p>Please use the form below to run test bundle(s), directories and more.</p>
<div class="form-group">
<label for="reporter">Reporter</label>
<select name="reporter" id="reporter" class="custom-select">
<cfloop array="#reporters#" index="thisReporter">
<option <cfif url.reporter eq thisReporter>selected="selected"</cfif> value="#thisReporter#">#thisReporter# Reporter</option>
</cfloop>
</select>
</div>
<div class="form-group">
<label for="directory">Directory Mapping</label>
<input class="form-control" type="text" name="directory" id="directory" value="#trim( url.directory )#" placeholder="Directory" />
</div>
<div class="form-group form-check">
<input class="form-check-input" title="Enable directory recursion for directory runner" name="recurse" id="recurse" type="checkbox" value="true" <cfif url.recurse>checked="true"</cfif> />
<label class="form-check-label" for="recurse"> Recurse Directories</label>
</div>
<div class="form-group">
<label for="bundles">Bundle(s)</label>
<input class="form-control" title="List of bundles to run" type="text" name="bundles" id="bundles" value="#url.bundles#" placeholder="Bundle(s)" />
</div>
<div class="form-group">
<label for="labels">Label(s)</label>
<input class="form-control" title="List of labels to apply to tests" type="text" name="labels" id="labels" value="#url.labels#" placeholder="Label(s)" />
</div>
<div class="form-group">
<label for="excludes">Excludes(s)</label>
<input class="form-control" title="List of labels to exclude from tests" type="text" name="excludes" id="excludes" value="#url.excludes#" placeholder="Excludes(s)" />
</div>
<div class="form-group">
<label for="reportpath">Report Path</label>
<input class="form-control" title="Report Path" type="text" name="reportpath" id="reportpath" value="#url.reportpath#" placeholder="Report Path" />
</div>
<div class="form-group form-check">
<input class="form-check-input" title="Include Properties Summary" name="propertiesSummary" id="propertiesSummary" type="checkbox" value="true" <cfif url.propertiesSummary>checked="true"</cfif> />
<label class="form-check-label" for="propertiesSummary"> Include Properties Summary</label>
</div>
<div class="form-group" id="propertiesInputs">
<div class="form-group">
<label for="propertiesFilename">Properties Filename</label>
<input class="form-control" title="Properties Filename" type="text" name="propertiesFilename" id="propertiesFilename" value="#url.propertiesFilename#" placeholder="Properties Filename" />
</div>
</div>
<div class="form-group form-check">
<input class="form-check-input" title="Enable code coverage report" name="coverageEnabled" id="coverageEnabled" type="checkbox" value="true" <cfif url.coverageEnabled>checked="true"</cfif> />
<label class="form-check-label" for="coverageEnabled"> Enable code coverage report</label>
</div>
<div class="form-group" id="coverageInputs">
<div class="form-group">
<label for="coverageSonarQubeXMLOutputPath">Coverage SonarQube XML Output Path</label>
<input class="form-control" title="Coverage SonarQube XML Output Path" type="text" name="coverageSonarQubeXMLOutputPath" id="coverageSonarQubeXMLOutputPath" value="#url.coverageSonarQubeXMLOutputPath#" placeholder="Coverage SonarQube XML Output Path" />
</div>
<div class="form-group">
<label for="coveragePathToCapture">Coverage Path to Capture</label>
<input class="form-control" title="Coverage path to Capture" type="text" name="coveragePathToCapture" id="coveragePathToCapture" value="#url.coveragePathToCapture#" placeholder="Coverage path to Capture" />
</div>
<div class="form-group">
<label for="coverageWhitelist">Coverage Whitelist</label>
<input class="form-control" title="Coverage Whitelist" type="text" name="coverageWhitelist" id="coverageWhitelist" value="#url.coverageWhitelist#" placeholder="Coverage Whitelist" />
</div>
<div class="form-group">
<label for="coverageBlacklist">Coverage Blacklist</label>
<input class="form-control" title="Coverage Blacklist" type="text" name="coverageBlacklist" id="coverageBlacklist" value="#url.coverageBlacklist#" placeholder="Coverage Blacklist" />
</div>
<div class="form-group">
<label for="coverageBrowserOutputDir">Coverage Browser Output Directory</label>
<input class="form-control" title="Coverage Browser Output Directory" type="text" name="coverageBrowserOutputDir" id="coverageBrowserOutputDir" value="#url.coverageBrowserOutputDir#" placeholder="Coverage Browser Output Directory" />
</div>
</div>
<div class="form-group">
<button class="btn btn-sm btn-primary" type="button" onclick="clearResults()">Clear</button>
<button class="btn btn-sm btn-primary" type="button" id="btn-run" title="Run all the tests" onclick="runTests()">Run</button>
</div>
</form>
</div>
</div>
</div>
<!--- Results --->
<div id="tb-results" class="container"></div>
</body>
</html>
</cfoutput>

0 comments on commit a862397

Please sign in to comment.