Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

spec-detective

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

spec-detective - npm Package Compare versions

Comparing version 0.0.9 to 0.1.0

lib/app.js

129

lib/configBuilder.js
/*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;

7

lib/featureTransformer.js

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc