spec-detective
Advanced tools
Comparing version
/*jslint node: true */ | ||
'use strict'; | ||
var colors = require('colors'); | ||
/** | ||
* "buildConfig" | ||
* | ||
* Collects input options from console or a config file. | ||
*/ | ||
function buildConfig(args) { | ||
var fs = require('fs'), | ||
config = {}, | ||
content; | ||
argv = require('minimist')(args.slice(2)), | ||
config, | ||
content, | ||
configFile; | ||
config.specFile = 'spec-file.json'; | ||
config.resultsFile = 'results-file.json'; | ||
/** | ||
* Below are some of the example inputs. | ||
* | ||
* --config=file.conf | ||
* --specs=.feature.md | ||
* --results=output.json,test.xml | ||
* --watch | ||
* --junit-out=junit-output.json | ||
* --specs-out=spec-file.json, | ||
* --results-out=results-file.json | ||
*/ | ||
if (fs.existsSync("spec-detective.conf.json")) { | ||
content = fs.readFileSync("spec-detective.conf.json", {encoding:"utf8"}); | ||
config = JSON.parse(content); | ||
/** | ||
* Default config. | ||
*/ | ||
config = { | ||
config: (argv.config !== undefined)? argv.config : 'spec-detective.conf.json', | ||
watch: false, | ||
specs: false, | ||
results: false, | ||
tags: [], | ||
'junit-out': 'junit-output.xml', | ||
'specs-out': 'spec-file.json', | ||
'results-out': 'results-file.json' | ||
} | ||
if (args[2] !== undefined) { | ||
config.specGlob = args[2]; | ||
/** | ||
* Overrides from config file. | ||
*/ | ||
if (fs.existsSync(config.config)) { | ||
content = fs.readFileSync(config.config, {encoding:"utf8"}); | ||
configFile = JSON.parse(content); | ||
for (var key in configFile) { | ||
if (configFile.hasOwnProperty(key)) { | ||
config[key] = configFile[key]; | ||
} | ||
} | ||
} | ||
if (args[3] !== undefined) { | ||
config.resultsGlob = args[3]; | ||
/** | ||
* Overrides from input. | ||
*/ | ||
for (var key in argv) { | ||
if (argv.hasOwnProperty(key)) { | ||
config[key] = argv[key]; | ||
} | ||
} | ||
if (config.specGlob === undefined) { | ||
throw new Error("A specs glob such as path/*.feature must be specified"); | ||
/** | ||
* Help. | ||
*/ | ||
if (argv['h'] || argv['help'] || args.length === 2) { | ||
console.log( | ||
'\nSpec Detective: A BDD tool minus the pain\n\n'.green + | ||
'Usage:\n' + | ||
' spec-detective <arguments>\n\n' + | ||
'Arguments:\n' + | ||
' --start=<configFile> Set a config file location.\n' + | ||
' --watch Start in watch mode.\n' + | ||
' --specs="<glob>" Feature files to read (eg "*/**/*.feature.md").\n' + | ||
' --results="<glob>" Comma-deliminated list of test output (eg "tests/*.xml,tests/*.json").\n' + | ||
' --tags=<tags> Comma-delinated list of tagged features to read.\n' + | ||
' --junit-out=<file> File name for junit output (default: junit-output.xml).\n' + | ||
' --specs-out=<file> File name for spec json output (default: spec-file.json).\n' + | ||
' --results-out=<file> File name for results json output (default: results-file.json).\n' | ||
); | ||
process.exit(); | ||
} | ||
if (config.resultsGlob === undefined) { | ||
throw new Error("A results file must be specified"); | ||
/** | ||
* Enrichment. | ||
*/ | ||
if (config.tags && config.tags.indexOf(',') !== -1) { | ||
config.tags = config.tags.split(','); | ||
} | ||
if (config.results && config.results.indexOf(',') !== -1) { | ||
config.results = config.results.split(','); | ||
} | ||
if (config.results && typeof config.results === 'string') { | ||
config.results = [config.results]; | ||
} | ||
/** | ||
* We ALWAYS need spec files and tests results. | ||
*/ | ||
if (!config.specs) { | ||
print("A specs glob such as path/*.feature must be specified.", "red"); | ||
} | ||
if (!config.results) { | ||
print("A results file must be specified.", "red"); | ||
} | ||
/** | ||
* Abstract print for tests. | ||
*/ | ||
function print (message, color) { | ||
if (args[1].indexOf('spec-detective') !== -1 || args[1].indexOf('shouldit') !== -1) { | ||
if (color === undefined) { | ||
console.log(message); | ||
return; | ||
} | ||
console.log(message[color]); | ||
} else { | ||
config.message = message; | ||
} | ||
} | ||
return config; | ||
} | ||
}; | ||
module.exports = buildConfig; |
@@ -1,6 +0,6 @@ | ||
function transformFeature(input, callback) { | ||
function transformFeature(input, tags, callback) { | ||
var parser = require('./markdownParser'), | ||
output = {}; | ||
parser(input, function(spec){ | ||
parser(input, tags, function(spec){ | ||
handleSpec(spec, output, callback); | ||
@@ -12,4 +12,5 @@ }); | ||
var current = getCurrentOutputPointer(spec.suite, output); | ||
var current; | ||
if(spec.description) { | ||
current = getCurrentOutputPointer(spec.suite, output); | ||
current[spec.description] = spec.line; | ||
@@ -16,0 +17,0 @@ } |
var lineReader = require('line-reader'); | ||
function parseMarkdown(file, callback) { | ||
var output = {suite: [], last: false}; | ||
function parseMarkdown(file, tags, callback) { | ||
var output = {suite: [], last: false, currentTag: false, currentTagLevel: false}; | ||
//TODO: Refactor these into modules to by DRY | ||
/** | ||
* TODO: Refactor these into modules to be more DRY | ||
* | ||
* We also need to make this more performant by not instantiating new | ||
* Regex's on each pass. | ||
* | ||
* We can also grab the content by matching it | ||
*/ | ||
var lineTypes = { | ||
@@ -53,2 +60,18 @@ 'SPEC' : { | ||
} | ||
}, | ||
'TAG' : { | ||
tokens: ['> @', '>@'], | ||
match: function(line) { | ||
for(var i = 0; i < this.tokens.length; i++) { | ||
var regex = new RegExp('\\' + this.tokens[i] + '([^\n]*)'); | ||
if(line.match(regex)) { | ||
return line.match(regex); | ||
} | ||
} | ||
return false; | ||
}, | ||
strip: function(line) { | ||
var regex = new RegExp('(> @ )', 'gi' ); | ||
return this.match(line)[1].replace(regex, ''); | ||
} | ||
} | ||
@@ -64,2 +87,3 @@ }; | ||
} | ||
output.description = false; | ||
output.line = getDescriptiveLine(file, lineCount); | ||
@@ -76,6 +100,19 @@ handleLine(line, callback); | ||
case 'SPEC': | ||
output.description = typeObject.strip(line); | ||
if ( | ||
(tags.length < 1) || | ||
tags.indexOf(output.currentTag) !== -1 | ||
) { | ||
output.description = typeObject.strip(line); | ||
} | ||
callback(output); | ||
return; | ||
case 'DESCRIBE': | ||
if (output.currentTagLevel && output.currentTagLevel == typeObject.level(line)) { | ||
output.currentTagLevel = false; | ||
output.currentTag = false; | ||
} | ||
if (output.currentTag && !output.currentTagLevel) { | ||
output.currentTagLevel = typeObject.level(line); | ||
} | ||
//place the describe at the correct level | ||
@@ -85,2 +122,3 @@ output.suite[typeObject.level(line) -1] = typeObject.strip(line); | ||
output.suite = output.suite.splice(0, typeObject.level(line)); | ||
return; | ||
@@ -90,2 +128,7 @@ case 'SKIP' : | ||
output.last = true; | ||
break; | ||
case 'TAG' : | ||
output.currentTag = typeObject.strip(line); | ||
output.currentTagLevel = false; | ||
break; | ||
} | ||
@@ -92,0 +135,0 @@ if(output.last) { |
@@ -14,4 +14,2 @@ /** | ||
resultsGlob = resultsGlob.split(","); | ||
for (var i = 0; i < resultsGlob.length; i++) { | ||
@@ -18,0 +16,0 @@ files = files.concat(glob.sync(resultsGlob[i])); |
/** | ||
* Get tht specs from a glob and merges the specs | ||
* Get the specs from a glob and merges the specs | ||
*/ | ||
function collectSpecs(specsGlob, callback) { | ||
function collectSpecs(specsGlob, tags, callback) { | ||
var featureTransformer = require('./featureTransformer'), | ||
@@ -18,3 +18,3 @@ glob = require("glob"), | ||
for (i = 0; i < files.length; i++) { | ||
featureTransformer(files[i], fileTransformerCallback); | ||
featureTransformer(files[i], tags, fileTransformerCallback); | ||
} | ||
@@ -21,0 +21,0 @@ }); |
{ | ||
"name": "spec-detective", | ||
"version": "0.0.9", | ||
"version": "0.1.0", | ||
"description": "A cool way to find out if your spec's in feature files and the like have met expectations.", | ||
@@ -47,3 +47,4 @@ "main": "index.js", | ||
"mocha-spec-json-reporter": "*", | ||
"grunt-contrib-jshint": "^0.10.0" | ||
"grunt-contrib-jshint": "^0.10.0", | ||
"minimist": "*" | ||
}, | ||
@@ -50,0 +51,0 @@ "dependencies": { |
@@ -16,9 +16,8 @@ { | ||
}, | ||
"Results1": { | ||
"should be able to have tests": "PASSED", | ||
"should be able to merge tests": "PASSED" | ||
"describe something": { | ||
"should do something": "PASSED" | ||
}, | ||
"Results2": { | ||
"should be able to other context based tests": "PASSED" | ||
"Feature Subfeature": { | ||
"has one spec": "FAILED" | ||
} | ||
} |
@@ -8,3 +8,3 @@ var buildConfig = require("../lib/configBuilder"), | ||
beforeEach(function(){ | ||
args = ["", "", "", ""]; | ||
args = ['node', '/mocha', '--specs=exampleSpec.feature', '--results=results.json,results.xml']; | ||
}); | ||
@@ -14,4 +14,4 @@ | ||
var glob = "tests/fixtures/spec/exampleSpec.feature"; | ||
args[2] = glob; | ||
assert.equal(buildConfig(args).specGlob, glob); | ||
args[2] = '--specs=' + glob; | ||
assert.equal(buildConfig(args).specs, glob); | ||
}); | ||
@@ -21,4 +21,4 @@ | ||
var comparisonFile = "tests/fixtures/spec/exampleSpec.feature"; | ||
args[3] = comparisonFile; | ||
assert.equal(buildConfig(args).resultsGlob, comparisonFile); | ||
args[3] = '--results=' + comparisonFile; | ||
assert.deepEqual(buildConfig(args).results, [comparisonFile]); | ||
}); | ||
@@ -28,3 +28,3 @@ | ||
args[2] = undefined; | ||
assert.throws(function() {buildConfig(args)}, Error, "A glob must be specified"); | ||
assert.equal(buildConfig(args).message, "A specs glob such as path/*.feature must be specified."); | ||
}); | ||
@@ -34,5 +34,15 @@ | ||
args[3] = undefined; | ||
assert.throws(function() {buildConfig(args)}, Error, "A comparison file must be specified"); | ||
assert.equal(buildConfig(args).message, "A results file must be specified."); | ||
}); | ||
it("should be able to add a comma deliminated tag", function() { | ||
args[4] = "--tags=richard,john"; | ||
assert.deepEqual(buildConfig(args).tags, ['richard', 'john']); | ||
}); | ||
it("should be turn results into an array", function() { | ||
args[3] = "--results=richard,john"; | ||
assert.deepEqual(buildConfig(args).results, ['richard', 'john']); | ||
}); | ||
}); |
@@ -47,3 +47,3 @@ var featureTransformer = require('../lib/featureTransformer'), | ||
featureTransformer(inputFile, function(data) { | ||
featureTransformer(inputFile, [], function(data) { | ||
assert.like(JSON.parse(data), expectedOutput); | ||
@@ -50,0 +50,0 @@ done(); |
@@ -8,3 +8,3 @@ var markdownParser = require('../lib/markdownParser'), | ||
var inputFile = "test/fixtures/markdown/exampleSpec.md"; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
assert.equal(spec.description, "should do something"); | ||
@@ -17,3 +17,3 @@ done(); | ||
var inputFile = "test/fixtures/markdown/describe.md"; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
assert.equal(spec.description, "should do something"); | ||
@@ -29,3 +29,3 @@ assert.equal(spec.suite.length, 1); | ||
var count = 0; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
count++; | ||
@@ -49,3 +49,3 @@ if(count == 2) { | ||
var count = 0; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
count++; | ||
@@ -64,3 +64,3 @@ if(count == 2) { | ||
var inputFile = "test/fixtures/markdown/skipStep.md"; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
assert.equal(spec.description, "a second spec"); | ||
@@ -77,3 +77,3 @@ assert.equal(spec.suite.length, 1); | ||
var count = 0; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
count++; | ||
@@ -90,3 +90,3 @@ if(count == 2) { | ||
var inputFile = "test/fixtures/markdown/skipFile.md"; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
assert.equal(spec.last, true); | ||
@@ -101,3 +101,3 @@ assert.equal(spec.skip, true); | ||
var inputFile = "test/fixtures/markdown/upperSkip.md"; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
assert.equal(spec.last, true); | ||
@@ -112,3 +112,3 @@ assert.equal(spec.skip, true); | ||
var inputFile = "test/fixtures/markdown/skipNoSpace.md"; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
assert.equal(spec.last, true); | ||
@@ -124,3 +124,3 @@ assert.equal(spec.skip, true); | ||
var count = 0; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
count++; | ||
@@ -136,3 +136,3 @@ if(count >= 2) { | ||
var inputFile = "test/fixtures/markdown/upperIT.md"; | ||
markdownParser(inputFile, function(spec) { | ||
markdownParser(inputFile, [], function(spec) { | ||
assert.equal(spec.description, "should do something"); | ||
@@ -143,3 +143,29 @@ done(); | ||
it("matches markers and returns only those specs when a marker is supplied", function(done) { | ||
var inputFile = "test/fixtures/markdown/markered.md", | ||
count = 0; | ||
markdownParser(inputFile, ["mymark"], function(spec) { | ||
count++; | ||
switch (count) { | ||
case 1: | ||
assert.equal(spec.currentTag, "ignoremark"); | ||
assert.equal(spec.description, false); | ||
break; | ||
case 2: | ||
assert.equal(spec.currentTag, "mymark"); | ||
assert.equal(spec.description, "also has a spec on the sub-sub feature"); | ||
break; | ||
case 3: | ||
assert.equal(spec.currentTag, "mymark"); | ||
assert.equal(spec.description, "also has a spec on another sub-sub feature"); | ||
break; | ||
case 4: | ||
assert.equal(spec.currentTag, false); | ||
assert.equal(spec.description, false); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}); |
@@ -30,3 +30,3 @@ var assert = require('assert'), | ||
it("should fire a callback passing in an object made up of merged objects", function(done) { | ||
resultCollector('test/fixtures/multiple_results/*.json', function(data) { | ||
resultCollector(['test/fixtures/multiple_results/*.json'], function(data) { | ||
assert.equal(JSON.stringify(data), JSON.stringify({ | ||
@@ -33,0 +33,0 @@ "Results1": { |
@@ -17,3 +17,3 @@ var assert = require('assert'), | ||
var object, | ||
transformer = function (file, callback) { | ||
transformer = function (file, tags, callback) { | ||
i++; | ||
@@ -46,3 +46,3 @@ object = {}; | ||
specCollector('test/fixtures/markdown/*.md', function(){}); | ||
specCollector('test/fixtures/markdown/*.md', [], function(){}); | ||
assert.equal(transformerSpy.callCount, 3); | ||
@@ -52,3 +52,3 @@ }); | ||
it("should fire a callback passing in an object made up of merged objects", function(done) { | ||
specCollector('test/fixtures/markdown/*.md', function(data) { | ||
specCollector('test/fixtures/markdown/*.md', [], function(data) { | ||
assert.equal(JSON.stringify(data), JSON.stringify({ | ||
@@ -55,0 +55,0 @@ 'some data1': 'some value', |
Sorry, the diff of this file is not supported yet
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
74361
9.69%56
5.66%1646
14.31%14
7.69%11
10%