UNPKG

3.19 kBJavaScriptView Raw
1'use strict';
2var fs = require('fs');
3var path = require('path');
4var dox = require('dox');
5var _ = require('lodash');
6var commentParser = require('./comment-parser');
7var util = require('./util');
8
9var JSDOCTEST_DISABLE = process.env.JSDOCTEST_DISABLE || false;
10
11/**
12 * Runs jsdoctests in some file, and reports the results to the command-line.
13 */
14
15exports.run = function jsdoctest$run(filename) {
16 require('should');
17 var content = fs.readFileSync(filename, 'utf8');
18
19 var jsdocTests = exports.getJsdoctests(content);
20 content += _.map(jsdocTests, exports.toJsdocRegister).join('');
21
22 global.__registerTest = exports.registerTest;
23 module._compile(util.stripBOM(content), filename);
24 delete global.__registerTest;
25
26 return exports.runRegistered();
27};
28
29/**
30 * Parses "jsdoctests" out of a file's contents and returns them. These are
31 * `dox` outputted `comment` nodes, overloaded with an `examples` field which
32 * adds `testCase` and `expectedResult` pairs to them.
33 */
34
35exports.getJsdoctests = function jsdoctest$getJsdoctests(content) {
36 var functionComments = _.filter(dox.parseComments(content), function(c) {
37 return c.ctx && (c.ctx.type === 'method' || c.ctx.type === 'function');
38 });
39
40 var comments = _.map(functionComments, function(comment) {
41 var exampleNodes = _.where(comment.tags, { type: 'example' });
42 var examples = _.flatten(_.map(exampleNodes, function(exampleNode) {
43 return commentParser.run(exampleNode.string);
44 }));
45
46 comment.examples = examples;
47 return examples.length ? comment : undefined;
48 });
49
50 return _.compact(comments);
51};
52
53var tests = [];
54
55/**
56 * Registers a test case to be run by the runner
57 */
58
59exports.registerTest = function jsdoctest$registerTest(id, fn) {
60 tests.push({
61 id: id,
62 fn: fn,
63 });
64};
65
66/**
67 * Runs test cases accumulated in the `tests` array.
68 */
69
70exports.runRegistered = function() {
71 var failed = false;
72
73 _.each(tests, function(test) {
74 console.log(test.id);
75 try {
76 test.fn();
77 } catch(err) {
78 console.error(err.toString());
79 failed = true;
80 }
81 });
82
83 return failed;
84};
85
86/**
87 * Compiles a jsdoc comment `dox` comment overloaded with the `examples` node to
88 * the internal test suite registering code.
89 */
90
91exports.toJsdocRegister = function jsdoctest$toJsdocRegister(comment) {
92 var baseId = comment.ctx.name + ' - ';
93 var compiled = _.map(comment.examples, function(example) {
94 var id = baseId + example.testCase + ' => ' + example.expectedResult;
95 var fn = 'function() {' +
96 '(' + example.testCase + ').should.equal(' + example.expectedResult + ');' +
97 '}';
98 return '__registerTest(\'' + id + '\', ' + fn + ');';
99 }).join('');
100
101 return '\n' + compiled;
102};
103
104// Mocha `--require` support:
105if(path.basename(process.argv[1]) === '_mocha' && !JSDOCTEST_DISABLE) {
106 var mocha = require('./mocha');
107 // Avoid circular require weirdness
108 if(module.parent.exports === mocha) {
109 // We could just always delete the cache, but I think this is clearer and
110 // shows explicitly what the circular problem is
111 delete require.cache[path.join(__dirname, 'mocha.js')];
112 mocha = require('./mocha');
113 }
114
115 mocha.toggleDoctestInjection();
116}