diff --git a/changelog.md b/changelog.md
index fb507c0..21e1de9 100644
--- a/changelog.md
+++ b/changelog.md
@@ -9,6 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+### Bugs
+
+- Using the `useTestBoxLocal` was not working correctly and re-downloading TestBox every time
+
+### Added
+
+- Updated the `run` command with tons of docs
+- Mutually exclusive options for `run` command which never existed before for `bundles` and `directory`
+
## [1.4.0] - 2024-02-29
### Added
diff --git a/commands/testbox/run.cfc b/commands/testbox/run.cfc
index 11b5ff9..8fdfa7f 100644
--- a/commands/testbox/run.cfc
+++ b/commands/testbox/run.cfc
@@ -81,16 +81,16 @@ component {
* Ability to execute TestBox tests
*
* @runner The URL or shortname of the runner to use, if it uses a short name we look in your box.json
- * @bundles The path or list of paths of the spec bundle CFCs to run and test
- * @directory The directory mapping to test: directory = the path to the directory using dot notation (myapp.testing.specs)
- * @recurse Recurse the directory mapping or not, by default it does
- * @reporter The type of reporter to use for the results, by default is uses our 'simple' report. You can pass in a core reporter string type or a class path to the reporter to use.
+ * @bundles The path or list of paths of the spec bundle CFCs to run and test ONLY
+ * @directory The directory to use to discover test bundles and specs to test. Mutually exclusive with bundles
. Example: directory=tests.specs
+ * @recurse Recurse the directory mapping or not. Defaults to true.
+ * @reporter The type of reporter to use for the results, by default is uses our 'json' reporter. You can pass in a core reporter string type or a class path to the reporter to use.
* @labels The list of labels that a suite or spec must have in order to execute.
* @excludes The list of labels that a suite or spec must not have in order to execute.
* @options Add adhoc URL options to the runner as options:name=value options:name2=value2
- * @testBundles A list or array of bundle names that are the ones that will be executed ONLY!
- * @testSuites A list of suite names that are the ones that will be executed ONLY!
- * @testSpecs A list of test names that are the ones that will be executed ONLY!
+ * @testBundles A list or array of bundle names that are the ones that will be focused on for execution based on the bundles
or directory
arguments.
+ * @testSuites A list of suite names that are the ones that will be focused on for execution based on the bundles
or directory
arguments.
+ * @testSpecs A list of test names that are the ones that will be focused on for execution based on the bundles
or directory
arguments.
* @outputFile We will store the results in this output file as well as presenting it to you.
* @outputFormats A list of output reporter to produce using the runner's JSON results only. Available formats are: json,xml,junit,antjunit,simple,dot,doc,min,mintext,doc,text,tap,codexwiki
* @verbose Display extra details including passing and skipped tests.
@@ -240,9 +240,20 @@ component {
/**
* Add runner options to URL
*
+ * We pass in ALL the arguments from the run
method and we will build out the URL from the options.
+ *
* @return The incorporated options and testing URL to hit
*/
private function addRunnerOptions(){
+ // Mutex options: If we have a directory, we can't have bundles
+ if ( len( arguments.directory ) ) {
+ arguments[ "bundles" ] = "";
+ }
+ // Mutex options: If we have bundles, we can't have directory
+ if ( len( arguments.bundles ) ) {
+ arguments[ "directory" ] = "";
+ }
+
// Get testbox options from package descriptor
var boxOptions = packageService.readPackageDescriptor( getCWD() ).testbox;
@@ -272,6 +283,7 @@ component {
var extraOptions = boxOptions.options ?: {};
// Add in command-specific options
extraOptions.append( arguments.options );
+
// Append to URL.
for ( var opt in extraOptions ) {
arguments.testboxURL &= "encodeForURL( opt )#=#encodeForURL( extraOptions[ opt ] )#";
@@ -421,15 +433,20 @@ component {
* @testboxUseLocal Use a local version of TestBox or in the execution path. Defaults to true, else it tries to download it
*/
private function ensureTestBox( boolean testboxUseLocal = true ){
- // Where it should go in module
+ // Where it should go in the module installed locally
var testBoxPath = variables.moduleConfig.path & "/testbox";
var modulePath = variables.moduleConfig.path;
- // Check if installed locally
- if ( arguments.testboxUseLocal ) {
- testBoxPath = resolvePath( "testbox" );
+ // If using local, check if we have a local version first
+ if( arguments.testboxUseLocal ){
+ // Check if we have a local version
+ var localTestBoxPath = resolvePath( "testbox" );
+ if( directoryExists( localTestBoxPath ) ){
+ testBoxPath = localTestBoxPath;
+ }
}
+ // If we don't have one by here, then download it
if ( !directoryExists( testBoxPath ) ) {
variables.print
.blackOnWheat1( " WARN " )