UNPKG

4.86 kBJavaScriptView Raw
1/*globals describe, before, it*/
2'use strict'
3
4var parse = require('./parse'),
5 fs = require('fs'),
6 path = require('path'),
7 MongoClient = require('mongodb').MongoClient,
8 baseContext = require('./baseContext'),
9 parseUrl = require('url').parse,
10 crypto = require('crypto')
11
12/**
13 * Execute the tests described by *.md files in a given folder
14 * @param {string} file The folder path
15 * @param {Object} options an object with optional keys:
16 * @param {string} options.mongoUri
17 * @param {string} options.baseUrl
18 * @param {string} [options.name='api']
19 * @param {boolean} [options.recursive=false]
20 * @param {boolean} [options.strict=true]
21 * @param {Object} [options.context]
22 * @param {string[]} [options.ignoredFindKeys=['_id', '__v']]
23 * @param {Buffer} [options.ca]
24 * @param {function(string):boolean} [options.filterFile]
25 * @param {function(Array<Header|Obj>, Test)} [options.preParse]
26 * @param {function(Test)} [options.onTest]
27 * @param {function(Test,Insertion|Clear|Declaration)} [options.onSetup]
28 * @param {function(Test,Case)} [options.onCase]
29 * @param {function(Case,*)} [options.onPost]
30 * @param {function(Case,*)} [options.onOut]
31 * @param {function(Case,Find)} [options.onFind]
32 * @param {Function} [options.describe]
33 * @param {Function} [options.before]
34 * @param {Function} [options.it]
35 * @param {Object<String, Object>} [options.defaultDocuments]
36 */
37module.exports = function (folder, options) {
38 options.mongoUri = validateMongoUri(options.mongoUri)
39
40 // Save defaultDocuments to baseContext to make it available for the script
41 baseContext.defaultDocuments = options.defaultDocuments || Object.create(null)
42
43 // Prepare options
44 options.name = options.name || 'api'
45 options.describe = options.describe || describe
46 options.before = options.before || before
47 options.it = options.it || it
48 options.context = options.context || {}
49 options.context.__proto__ = baseContext
50 options.recursive = options.recursive || false
51 options.strict = options.strict === undefined ? true : options.strict
52 options.filterFile = options.filterFile || function () {
53 return true
54 }
55 options.preParse = options.preParse || function () {}
56 options.ignoredFindKeys = options.ignoredFindKeys || ['_id', '__v']
57
58 options.describe(options.name, function () {
59 options.before(function (done) {
60 // Connect to mongo
61 MongoClient.connect(options.mongoUri, function (err, db) {
62 if (err) {
63 return done(err)
64 }
65 options.db = db
66 done()
67 })
68 })
69
70 // Load files
71 walk(options.recursive, folder, function (file) {
72 if (file.substr(-3) === '.md' && options.filterFile(file)) {
73 var test = parse(file, fs.readFileSync(file, 'utf8'), options.preParse)
74 if (options.onTest) {
75 options.onTest(test)
76 }
77 test.execute(options)
78 }
79 })
80 })
81}
82
83/**
84 * @class
85 */
86module.exports.Header = require('./classes/Header')
87
88/**
89 * @class
90 */
91module.exports.Obj = require('./classes/Obj')
92
93/**
94 * @class
95 */
96module.exports.ParseError = require('./classes/ParseError')
97
98/**
99 * Make sure the mongo uri has 'localhost' as hostname and 'test' in the DB name
100 * @param {string} mongoUri
101 */
102function validateMongoUri(mongoUri) {
103 var tag, rightTag, sha
104 if (mongoUri.match(/^![a-z0-9]{10}!/)) {
105 // Extract tag
106 tag = mongoUri.substr(1, 10)
107 mongoUri = mongoUri.substr(12)
108 }
109
110 if (mongoUri.indexOf('test') === -1 || parseUrl(mongoUri).hostname !== 'localhost') {
111 // Propably an error, we force the mongoUri to be localhost and the DB/username to be test
112 sha = crypto.createHash('sha1')
113 sha.end(new Buffer(mongoUri))
114 rightTag = sha.read().toString('hex').substr(0, 10)
115 }
116
117 // Compare tags
118 if (tag !== rightTag) {
119 console.log('++++++++++')
120 if (rightTag) {
121 console.log('The mongoUri "' + mongoUri.substr(0, 17) + '..." seems not to be test-safe')
122 console.log('I recommend you to connect to a localhost instance and a database with "test" in the name')
123 console.log('Remember that the database is DROPPED before every test!')
124 console.log('If you are really sure, please prepend "!' + rightTag + '!" to your mongoUri')
125 console.log('Like this: "!' + rightTag + '!' + mongoUri.substr(0, 17) + '..."')
126 } else {
127 console.log('Please remove the !tag! from the mongoUri to run the test')
128 }
129 console.log('++++++++++')
130 throw new Error('Invalid protection tag')
131 }
132 return mongoUri
133}
134
135/**
136 * Call a function for each file in a given directory
137 * @param {boolean} recursive
138 * @param {string} dir
139 * @param {Function} fn
140 */
141function walk(recursive, dir, fn) {
142 fs.readdirSync(dir).forEach(function (item) {
143 item = path.join(dir, item)
144 if (fs.statSync(item).isDirectory()) {
145 if (recursive) {
146 walk(recursive, item, fn)
147 }
148 } else {
149 fn(item)
150 }
151 })
152}
\No newline at end of file