mirror of
https://github.com/SrIzan10/nodemon.git
synced 2026-05-01 10:55:09 +00:00
78 tests passing on mac.
This commit is contained in:
@@ -2,21 +2,21 @@
|
||||
|
||||
nodemon will emit events based on the child process.
|
||||
|
||||
## States
|
||||
|
||||
- start
|
||||
- crash
|
||||
- exit
|
||||
- restart
|
||||
- config:update
|
||||
- log, args: type, message (plain text log), colour (colour coded log)
|
||||
|
||||
## Commands
|
||||
|
||||
- restart
|
||||
- config:update
|
||||
- quit
|
||||
|
||||
## States
|
||||
|
||||
- start - child process has started
|
||||
- crash - child process has crashed (nodemon will not emit exit)
|
||||
- exit - child process has cleanly exited (ie. no crash)
|
||||
- restart - child process has restarted
|
||||
- config:update - nodemon's config has changed
|
||||
- log({ type, message (plain text log), colour (colour coded log) }) - logging from nodemon (not the child process)
|
||||
|
||||
## Using nodemon events
|
||||
|
||||
If nodemon is required, events can be bound and emitted on the nodemon object:
|
||||
|
||||
@@ -139,8 +139,6 @@ function loadFile(options, config, dir, ready) {
|
||||
return callback({});
|
||||
}
|
||||
|
||||
utils.log.detail('reading config ' + filename);
|
||||
|
||||
var settings = {};
|
||||
|
||||
try {
|
||||
|
||||
@@ -60,23 +60,29 @@ function run(options) {
|
||||
signal = 'SIGUSR2';
|
||||
}
|
||||
|
||||
bus.emit('exit');
|
||||
if (signal === 'SIGUSR2' || code === 0) {
|
||||
// this was a clean exit, so emit exit, rather than crash
|
||||
bus.emit('exit');
|
||||
|
||||
// exit the monitor, but do it gracefully
|
||||
if (signal === 'SIGUSR2') {
|
||||
// restart
|
||||
restart();
|
||||
} else if (code === 0) { // clean exit - wait until file change to restart
|
||||
utils.log.status('clean exit - waiting for changes before restart');
|
||||
child = null;
|
||||
} else if (options.exitcrash) {
|
||||
utils.log.fail('app crashed');
|
||||
bus.emit('crash');
|
||||
process.exit(0);
|
||||
// exit the monitor, but do it gracefully
|
||||
if (signal === 'SIGUSR2') {
|
||||
// restart
|
||||
restart();
|
||||
} else if (code === 0) { // clean exit - wait until file change to restart
|
||||
utils.log.status('clean exit - waiting for changes before restart');
|
||||
child = null;
|
||||
}
|
||||
} else {
|
||||
utils.log.fail('app crashed - waiting for file changes before starting...');
|
||||
child = null;
|
||||
bus.emit('crash');
|
||||
if (options.exitcrash) {
|
||||
utils.log.fail('app crashed');
|
||||
if (!config.required) {
|
||||
process.exit(0);
|
||||
}
|
||||
} else {
|
||||
utils.log.fail('app crashed - waiting for file changes before starting...');
|
||||
child = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -151,6 +157,8 @@ bus.on('quit', function () {
|
||||
exit = noop; // null out in case of race condition
|
||||
if (!config.required) {
|
||||
process.exit(0);
|
||||
} else {
|
||||
bus.emit('exit');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ function filterAndRestart(files) {
|
||||
utils.log.detail(path.relative(process.cwd(), file));
|
||||
});
|
||||
if (config.options.verbose) {
|
||||
console.log();
|
||||
utils.log._log('');
|
||||
}
|
||||
|
||||
bus.emit('restart');
|
||||
|
||||
@@ -15,16 +15,13 @@ config.required = utils.isRequired;
|
||||
|
||||
function nodemon(settings) {
|
||||
nodemon.removeAllListners();
|
||||
utils.reset();
|
||||
|
||||
// set the debug flag as early as possible to get all the detailed logging
|
||||
if (settings.verbose) {
|
||||
utils.debug = true;
|
||||
}
|
||||
|
||||
if (config.required) {
|
||||
utils.quiet();
|
||||
}
|
||||
|
||||
if (typeof settings === 'string') {
|
||||
settings = cli.parse(settings);
|
||||
}
|
||||
@@ -160,7 +157,11 @@ nodemon.removeAllListners = function (event) {
|
||||
Object.keys(eventHandlers).filter(function (e) {
|
||||
return event ? e === event : true;
|
||||
}).forEach(function (event) {
|
||||
eventHandlers[event].forEach(bus.removeListener.bind(bus, event));
|
||||
eventHandlers[event].forEach(function (handler) {
|
||||
bus.removeListener(event, handler);
|
||||
eventHandlers[event].splice(eventHandlers[event].indexOf(handler), 0);
|
||||
});
|
||||
// delete eventHandlers[event];
|
||||
});
|
||||
|
||||
return nodemon;
|
||||
@@ -172,10 +173,10 @@ nodemon.config = config;
|
||||
|
||||
// on exception *inside* nodemon, shutdown wrapped node app
|
||||
process.on('uncaughtException', function (err) {
|
||||
utils.log.error('exception in nodemon killing node');
|
||||
utils.log.error(err.stack);
|
||||
console.log();
|
||||
utils.log.error('If appropriate, please file an error: http://github.com/remy/nodemon/issues/new\n');
|
||||
console.error('exception in nodemon killing node');
|
||||
console.error(err.stack);
|
||||
console.error();
|
||||
console.error('If appropriate, please file an error: http://github.com/remy/nodemon/issues/new\n');
|
||||
if (!config.required) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,17 @@ var utils = module.exports = {
|
||||
// nukes the logging
|
||||
if (!this.debug) {
|
||||
Object.keys(this.log).forEach(function (method) {
|
||||
this.log[method] = noop;
|
||||
// this.log[method] = noop;
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
reset: function () {
|
||||
if (!this.debug) {
|
||||
Object.keys(this.log).forEach(function (method) {
|
||||
// delete this.log[method];
|
||||
}.bind(this));
|
||||
}
|
||||
this.debug = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ var coding = {
|
||||
};
|
||||
|
||||
function log(type, text) {
|
||||
var msg = colour(coding[type], '[nodemon] ' + text);
|
||||
var msg = colour(coding[type], '[nodemon] ' + (text||''));
|
||||
|
||||
if (required) {
|
||||
bus.emit('log', { type: type, message: text, colour: msg });
|
||||
@@ -25,25 +25,38 @@ function log(type, text) {
|
||||
}
|
||||
}
|
||||
|
||||
var logger = function (r) {
|
||||
required = r;
|
||||
|
||||
return logger;
|
||||
var Logger = function (r) {
|
||||
if (!(this instanceof Logger)) {
|
||||
return new Logger(r);
|
||||
}
|
||||
this.required(r);
|
||||
return this;
|
||||
};
|
||||
|
||||
Object.keys(coding).forEach(function (type) {
|
||||
logger[type] = log.bind(null, type);
|
||||
Logger.prototype[type] = log.bind(null, type);
|
||||
});
|
||||
|
||||
// detail is for messages that are turned on during debug
|
||||
logger.detail = function (msg) {
|
||||
Logger.prototype.detail = function (msg) {
|
||||
if (this.debug) {
|
||||
log('detail', msg);
|
||||
}
|
||||
};
|
||||
|
||||
logger.debug = false;
|
||||
Logger.prototype.required = function (val) {
|
||||
required = val;
|
||||
};
|
||||
|
||||
logger._log = log;
|
||||
Logger.prototype.debug = false;
|
||||
Logger.prototype._log = function (type, msg) {
|
||||
if (required) {
|
||||
bus.emit('log', { type: type, message: msg, colour: msg });
|
||||
} else if (type === 'error') {
|
||||
util.error(msg);
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = logger;
|
||||
module.exports = Logger;
|
||||
@@ -33,7 +33,8 @@
|
||||
"main": "./test/fixtures/app.js",
|
||||
"scripts": {
|
||||
"coverage": "istanbul cover _mocha -- --timeout 15000 --ui bdd --reporter list test/**/*.test.js",
|
||||
"test": "node_modules/mocha/bin/_mocha --timeout 15000 --ui bdd --reporter list test/**/*.test.js"
|
||||
"test": "node_modules/mocha/bin/_mocha --timeout 15000 --ui bdd --reporter list test/**/*.test.js",
|
||||
"web": "node web"
|
||||
},
|
||||
"devDependencies": {
|
||||
"connect": "*",
|
||||
|
||||
@@ -9,13 +9,11 @@ var load = require('../../lib/config/load'),
|
||||
|
||||
describe('config load', function () {
|
||||
var pwd = process.cwd(),
|
||||
oldhome = utils.home,
|
||||
log = utils.clone(utils.log);
|
||||
oldhome = utils.home;
|
||||
|
||||
afterEach(function () {
|
||||
process.chdir(pwd);
|
||||
utils.home = oldhome;
|
||||
utils.log = log;
|
||||
});
|
||||
|
||||
function removeRegExp(options) {
|
||||
@@ -23,14 +21,14 @@ describe('config load', function () {
|
||||
delete options.ignore.re;
|
||||
}
|
||||
|
||||
utils.quiet();
|
||||
|
||||
beforeEach(function () {
|
||||
// move to the fixtures directory to allow for config loading
|
||||
process.chdir(path.resolve(pwd, 'test/fixtures'));
|
||||
utils.home = path.resolve(pwd, ['test', 'fixtures', 'global'].join(path.sep));
|
||||
|
||||
rules.reset();
|
||||
|
||||
utils.quiet();
|
||||
});
|
||||
|
||||
it('should support old .nodemonignore', function (done) {
|
||||
|
||||
@@ -4,9 +4,9 @@ var watchable = require('../../lib/config/watchable'),
|
||||
bus = require('../../lib/utils/bus'),
|
||||
assert = require('assert');
|
||||
|
||||
bus.on('log', function (event) {
|
||||
console.log(event.colour);
|
||||
});
|
||||
// bus.on('log', function (event) {
|
||||
// console.log(event.colour);
|
||||
// });
|
||||
|
||||
describe('watchable tests', function () {
|
||||
it('should return whether watch is supported', function (done) {
|
||||
|
||||
83
test/fork/watch-restart.test.js
Normal file
83
test/fork/watch-restart.test.js
Normal file
@@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
/*global describe:true, it: true, after: true */
|
||||
var nodemon = require('../../lib/'),
|
||||
assert = require('assert'),
|
||||
fs = require('fs'),
|
||||
utils = require('../utils'),
|
||||
colour = require('../../lib/utils/colour'),
|
||||
appjs = utils.appjs,
|
||||
run = utils.run,
|
||||
cleanup = utils.cleanup,
|
||||
path = require('path'),
|
||||
touch = require('touch'),
|
||||
crypto = require('crypto'),
|
||||
baseFilename = 'test/fixtures/test' + crypto.randomBytes(16).toString('hex');
|
||||
|
||||
describe('nodemon fork child restart', function () {
|
||||
var tmpjs = path.resolve(baseFilename + '.js'),
|
||||
tmpmd = path.resolve(baseFilename + '.md');
|
||||
|
||||
after(function () {
|
||||
fs.unlink(tmpjs);
|
||||
fs.unlink(tmpmd);
|
||||
// clean up just in case.
|
||||
nodemon.emit('quit');
|
||||
nodemon.removeAllListners();
|
||||
});
|
||||
|
||||
it('should happen when monitoring a single extension', function (done) {
|
||||
fs.writeFileSync(tmpjs, 'true;');
|
||||
|
||||
var p = run('--ext js ' + appjs, {
|
||||
error: function (data) {
|
||||
p.send('quit');
|
||||
cleanup(p, done, new Error(data));
|
||||
}
|
||||
});
|
||||
|
||||
p.on('message', function (event) {
|
||||
if (event.type === 'start') {
|
||||
setTimeout(function () {
|
||||
touch.sync(tmpjs);
|
||||
}, 1000);
|
||||
} else if (event.type === 'restart') {
|
||||
assert(true, 'nodemon restarted');
|
||||
nodemon.emit('quit');
|
||||
nodemon.removeAllListners();
|
||||
cleanup(p, done);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should happen when monitoring multiple extensions', function (done) {
|
||||
fs.writeFileSync(tmpjs, 'true;');
|
||||
fs.writeFileSync(tmpmd, '# true');
|
||||
setTimeout(function () {
|
||||
var p = run('--ext js,md ' + appjs, {
|
||||
error: function (data) {
|
||||
p.send('quit');
|
||||
cleanup(p, done, new Error(data));
|
||||
},
|
||||
output: function (data) {
|
||||
var msg = colour.strip(data.trim());
|
||||
if (utils.match(msg, 'changes after filters')) {
|
||||
var changes = msg.slice(-5).split('/');
|
||||
var restartedOn = changes.pop();
|
||||
assert(restartedOn === '1', 'nodemon restarted on a single file change');
|
||||
nodemon.emit('quit');
|
||||
nodemon.removeAllListners();
|
||||
cleanup(p, done);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
p.on('message', function (event) {
|
||||
if (event.type === 'start') {
|
||||
setTimeout(function () {
|
||||
touch.sync(tmpmd);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
@@ -25,7 +25,7 @@ describe('when nodemon runs', function () {
|
||||
|
||||
setTimeout(function () {
|
||||
fs.writeFileSync(tmp, 'var n = 10 + 2;');
|
||||
}, 500);
|
||||
}, 1000);
|
||||
}).on('restart', function () {
|
||||
assert(true, 'nodemon restarted');
|
||||
nodemon.emit('quit');
|
||||
@@ -66,7 +66,7 @@ describe('when nodemon runs', function () {
|
||||
// });
|
||||
|
||||
process.kill(process.pid, 'SIGINT');
|
||||
}, 500);
|
||||
}, 1000);
|
||||
}).on('crash', function () {
|
||||
assert(false, 'detected crashed state');
|
||||
}).on('exit', function () {
|
||||
@@ -77,7 +77,7 @@ describe('when nodemon runs', function () {
|
||||
|
||||
setTimeout(function () {
|
||||
process.kill(process.pid, 'SIGINT');
|
||||
}, 500);
|
||||
}, 1000);
|
||||
|
||||
});
|
||||
|
||||
|
||||
68
test/monitor/watch-restart.test.js
Normal file
68
test/monitor/watch-restart.test.js
Normal file
@@ -0,0 +1,68 @@
|
||||
'use strict';
|
||||
/*global describe:true, it: true, after: true */
|
||||
var nodemon = require('../../lib/'),
|
||||
assert = require('assert'),
|
||||
fs = require('fs'),
|
||||
utils = require('../utils'),
|
||||
bus = require('../../lib/utils/bus'),
|
||||
path = require('path'),
|
||||
touch = require('touch'),
|
||||
crypto = require('crypto'),
|
||||
baseFilename = 'test/fixtures/test' + crypto.randomBytes(16).toString('hex');
|
||||
|
||||
describe('nodemon child restart', function () {
|
||||
var tmpjs = path.resolve(baseFilename + '.js'),
|
||||
tmpmd = path.resolve(baseFilename + '.md');
|
||||
|
||||
after(function (done) {
|
||||
fs.unlink(tmpjs);
|
||||
fs.unlink(tmpmd);
|
||||
// clean up just in case.
|
||||
bus.once('exit', done);
|
||||
nodemon.emit('quit');
|
||||
nodemon.removeAllListners();
|
||||
});
|
||||
|
||||
it('should happen when monitoring a single extension', function (done) {
|
||||
fs.writeFileSync(tmpjs, 'true;');
|
||||
|
||||
nodemon({ script: tmpjs, verbose: true, ext: 'js' }).on('start', function () {
|
||||
setTimeout(function () {
|
||||
touch.sync(tmpjs);
|
||||
}, 1000);
|
||||
}).on('restart', function () {
|
||||
assert(true, 'nodemon restarted');
|
||||
bus.once('exit', done);
|
||||
nodemon.emit('quit');
|
||||
nodemon.removeAllListners();
|
||||
});
|
||||
});
|
||||
|
||||
it('should happen when monitoring multiple extensions', function (done) {
|
||||
setTimeout(function () {
|
||||
fs.writeFileSync(tmpjs, 'true;');
|
||||
fs.writeFileSync(tmpmd, '# true');
|
||||
|
||||
nodemon({
|
||||
script: tmpjs,
|
||||
ext: 'js md',
|
||||
verbose: true
|
||||
}).on('start', function () {
|
||||
setTimeout(function () {
|
||||
touch.sync(tmpmd);
|
||||
}, 1000);
|
||||
}).on('log', function (event) {
|
||||
// console.log(event.message);
|
||||
var msg = event.message;
|
||||
if (utils.match(msg, 'changes after filters')) {
|
||||
var changes = msg.trim().slice(-5).split('/');
|
||||
var restartedOn = changes.pop();
|
||||
assert(restartedOn === '1', 'nodemon restarted on a single file change');
|
||||
bus.once('exit', done);
|
||||
nodemon.emit('quit');
|
||||
nodemon.removeAllListners();
|
||||
}
|
||||
});
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
49
test/utils/log.test.js
Normal file
49
test/utils/log.test.js
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
/*global describe:true, it: true */
|
||||
var logger = require('../../lib/utils/log')(true),
|
||||
bus = require('../../lib/utils/bus'),
|
||||
colour = require('../../lib/utils/colour'),
|
||||
assert = require('assert');
|
||||
|
||||
describe('logger', function () {
|
||||
var types = {
|
||||
log: 'black',
|
||||
info: 'yellow',
|
||||
status: 'green',
|
||||
detail: 'yellow',
|
||||
fail: 'red',
|
||||
error: 'red'
|
||||
};
|
||||
|
||||
logger.debug = true;
|
||||
|
||||
Object.keys(types).forEach(function (type) {
|
||||
it('should .' + type, function (done) {
|
||||
bus.once('log', function (event) {
|
||||
assert(event.message === type);
|
||||
assert(event.colour.indexOf(colour[types[type]]) !== -1);
|
||||
done();
|
||||
});
|
||||
logger[type](type);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not log detail if debug is off', function (done) {
|
||||
logger.debug = false;
|
||||
|
||||
function handler() {
|
||||
assert(false, 'logged a message when we should not have done');
|
||||
bus.removeListener('log', handler);
|
||||
done();
|
||||
}
|
||||
|
||||
bus.addListener('log', handler);
|
||||
|
||||
logger.detail('detail');
|
||||
|
||||
setTimeout(function () {
|
||||
bus.removeListener('log', handler);
|
||||
done();
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user