Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support directory arguments in the CLI #77

Merged
merged 3 commits into from
Dec 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 45 additions & 6 deletions bin/src/cli-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const JsonFileRegex = /\.json{1}$/;
const mapJsonErrors = errors => errors.map(e => ` ${e.message}`).join('\n');
const ERRORS = {
NOT_FOUND: ' File not found.',
NOT_JSON: ' You must supply a valid JSON file.',
GENERIC: ' There was a problem loading mochawesome data.',
INVALID_JSON: errMsgs => mapJsonErrors(errMsgs),
IS_DIR: ' Directories are not supported (yet).'
Expand Down Expand Up @@ -42,8 +41,6 @@ function validateFile(file) {
err = ERRORS.NOT_FOUND;
} else if (e.code === 'EISDIR') {
err = ERRORS.IS_DIR;
} else if (!JsonFileRegex.test(file)) {
err = ERRORS.NOT_JSON;
} else if (JsonErrRegex.test(e.message)) {
err = ERRORS.INVALID_JSON([ e ]);
} else {
Expand Down Expand Up @@ -111,11 +108,17 @@ function handleResolved(resolvedValues) {
.join('\n\n'));
process.exitCode = 1;
}

if (!validFiles && !errors.length) {
logger.info(chalk.yellow('\nDid not find any JSON files to process.'));
process.exitCode = 1;
}

return resolvedValues;
}

/**
* Get the reportFilename option to be passed to report.create
* Get the reportFilename option to be passed to `report.create`
*
* Returns the `reportFilename` option if provided otherwise
* it returns the base filename stripped of path and extension
Expand All @@ -129,6 +132,42 @@ function getReportFilename({ filename }, { reportFilename }) {
return reportFilename || filename.split(path.sep).pop().replace(JsonFileRegex, '');
}

/**
* Process arguments, recursing through any directories,
* to find and validate JSON files
*
* @param {array} args Array of paths
* @param {array} files Array to populate
*
* @return {array} File objects to be processed
*/
function processArgs(args, files = []) {
return args.reduce((acc, arg) => {
let stats;
try {
stats = fs.statSync(arg);
} catch (err) {
// Do nothing
}

// If argument is a directory, process the files inside
if (stats && stats.isDirectory()) {
return processArgs(
fs.readdirSync(arg).map(file => path.join(arg, file)),
files
);
}

// If `statSync` failed, validating will handle the error
// If the argument is a file, check if its a JSON file before validating
if (!stats || JsonFileRegex.test(arg)) {
acc.push(validateFile(arg));
}

return acc;
}, files);
}

/**
* Main CLI Program
*
Expand All @@ -140,8 +179,8 @@ function marge(args) {
// Reset valid files count
validFiles = 0;

// Load and validate each file
const files = args._.map(validateFile);
// Get the array of JSON files to process
const files = processArgs(args._);

// When there are multiple valid files OR the timestamp option is set
// we must force `overwrite` to `false` to ensure all reports are created
Expand Down
7 changes: 4 additions & 3 deletions bin/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ const PercentClass = t.enums.of([ 'success', 'warning', 'danger' ], 'PercentClas
const TestState = t.enums.of([ 'passed', 'failed' ], 'TestState');
const TestSpeed = t.enums.of([ 'slow', 'medium', 'fast' ], 'TestSpeed');
const DateString = t.refinement(t.String, isISO8601, 'DateString');
const Duration = t.maybe(t.Integer);
const Uuid = t.refinement(t.String, isUUID, 'UUID');

const Test = t.struct({
title: t.String,
fullTitle: t.String,
timedOut: t.Boolean,
duration: t.Integer,
duration: Duration,
state: t.maybe(TestState),
speed: t.maybe(TestSpeed),
pass: t.Boolean,
Expand Down Expand Up @@ -43,7 +44,7 @@ Suite.define(t.struct({
failures: t.list(Uuid),
pending: t.list(Uuid),
skipped: t.list(Uuid),
duration: t.Integer,
duration: Duration,
rootEmpty: t.maybe(t.Boolean)
}));

Expand All @@ -56,7 +57,7 @@ const TestReport = t.struct({
failures: t.Integer,
start: DateString,
end: DateString,
duration: t.Integer,
duration: Duration,
testsRegistered: t.Integer,
passPercent: t.Number,
pendingPercent: t.Number,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
"chai-enzyme": "^1.0.0-beta.0",
"chart.js": "^2.3.0",
"classnames": "^2.2.5",
"cross-env": "^5.1.1",
"cross-env": "5.1.1",
"css-loader": "^0.28.0",
"css-modules-require-hook": "^4.0.5",
"enzyme": "^3.1.0",
Expand Down
115 changes: 115 additions & 0 deletions test/sample-data/sub/single.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{
"stats": {
"suites": 1,
"tests": 1,
"passes": 0,
"pending": 0,
"failures": 1,
"start": "2017-06-05T12:27:21.360Z",
"end": "2017-06-05T12:27:21.376Z",
"duration": 16,
"testsRegistered": 1,
"passPercent": 0,
"pendingPercent": 0,
"other": 0,
"hasOther": false,
"skipped": 0,
"hasSkipped": false,
"passPercentClass": "danger",
"pendingPercentClass": "danger"
},
"suites": {
"title": "",
"suites": [
{
"title": "Main Suite",
"suites": [],
"tests": [
{
"title": "should be false",
"fullTitle": "Main Suite should be false",
"timedOut": false,
"duration": 4,
"state": "failed",
"pass": false,
"fail": true,
"pending": false,
"code": "// true.should.eql(bool);\nexp.should.eql({\n foo: true,\n bar: true,\n baz: 1\n});\nshouldAddContext && addContext(this, 'context');",
"err": {
"operator": "to equal",
"expected": "{\n \"bar\": true\n \"baz\": 1\n \"foo\": true\n}",
"details": "at bar, A has false and B has true",
"showDiff": true,
"actual": "{\n \"bar\": false\n \"baz\": 1\n \"foo\": true\n}",
"negate": false,
"assertion": {
"obj": {
"foo": true,
"bar": false,
"baz": 1
},
"anyOne": false,
"negate": false,
"params": {
"operator": "to equal",
"expected": {
"foo": true,
"bar": true,
"baz": 1
},
"details": "at bar, A has false and B has true",
"showDiff": true,
"actual": {
"foo": true,
"bar": false,
"baz": 1
},
"negate": false,
"assertion": "[Circular ~.suites.suites.0.tests.0.err.assertion]"
},
"light": false
},
"_message": "expected Object { foo: true, bar: false, baz: 1 } to equal Object { foo: true, bar: true, baz: 1 } (at bar, A has false and B has true)",
"generatedMessage": true,
"estack": "AssertionError: expected Object { foo: true, bar: false, baz: 1 } to equal Object { foo: true, bar: true, baz: 1 } (at bar, A has false and B has true)\n at Assertion.fail (node_modules/should/cjs/should.js:258:17)\n at Assertion.value (node_modules/should/cjs/should.js:335:19)\n at Context.<anonymous> (helpers.js:26:20)",
"diff": " {\n- \"bar\": false\n+ \"bar\": true\n \"baz\": 1\n \"foo\": true\n }\n"
},
"isRoot": false,
"uuid": "65ef9d51-2e7b-4155-9d46-af6ad7d0e2d4",
"parentUUID": "37685726-1c47-4e1f-a7d4-6c88ebf842f9",
"isHook": false,
"skipped": false
}
],
"pending": [],
"root": false,
"_timeout": 2000,
"file": "/cases/test.js",
"uuid": "37685726-1c47-4e1f-a7d4-6c88ebf842f9",
"beforeHooks": [],
"afterHooks": [],
"fullFile": "/Users/adamgruber/Sites/ma-test/cases/test.js",
"passes": [],
"failures": ["65ef9d51-2e7b-4155-9d46-af6ad7d0e2d4"],
"skipped": [],
"duration": 4,
"rootEmpty": false
}
],
"tests": [],
"pending": [],
"root": true,
"_timeout": 2000,
"uuid": "005cc237-6ddd-4da6-8b5c-e82c1ee5cfdc",
"beforeHooks": [],
"afterHooks": [],
"fullFile": "",
"file": "",
"passes": [],
"failures": [],
"skipped": [],
"duration": 0,
"rootEmpty": true
},
"copyrightYear": 2017
}
24 changes: 11 additions & 13 deletions test/spec/cli/cli-main.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,23 @@ describe('bin/cli', () => {
});
});

describe('when file is a directory', () => {
it('should not create a report', () => {
const args = getArgs([ 'test/sample-data/' ]);
return expect(cli(args)).to.become([ {
filename: 'test/sample-data/',
data: undefined,
err: ' Directories are not supported (yet).'
} ]);
describe('when arg is a directory', () => {
beforeEach(() => {
createStub.onCall(0).resolves('mochawesome-report/single.html');
});

it('should create a report', () => {
const args = getArgs([ 'test/sample-data/sub' ]);
return expect(cli(args)).to.become([
'mochawesome-report/single.html'
]);
});
});

describe('when file is not JSON', () => {
it('should not create a report', () => {
const args = getArgs([ 'README.md' ]);
return expect(cli(args)).to.become([ {
filename: 'README.md',
data: undefined,
err: ' You must supply a valid JSON file.'
} ]);
return expect(cli(args)).to.become([]);
});
});

Expand Down