UNPKG

ylog

Version:

Why another logger? That's a good question!

623 lines (496 loc) 15.1 kB
'use strict'; /* ASSERT: ok(value, [message]) - Tests if value is a true value. equal(actual, expected, [message]) - Tests shallow, coercive equality with the equal comparison operator ( == ). notEqual(actual, expected, [message]) - Tests shallow, coercive non-equality with the not equal comparison operator ( != ). deepEqual(actual, expected, [message]) - Tests for deep equality. notDeepEqual(actual, expected, [message]) - Tests for any deep inequality. strictEqual(actual, expected, [message]) - Tests strict equality, as determined by the strict equality operator ( === ) notStrictEqual(actual, expected, [message]) - Tests strict non-equality, as determined by the strict not equal operator ( !== ) throws(block, [error], [message]) - Expects block to throw an error. doesNotThrow(block, [error], [message]) - Expects block not to throw an error. ifError(value) - Tests if value is not a false value, throws if it is a true value. Useful when testing the first argument, error in callbacks. SHOULD.JS: http://shouldjs.github.io/ Some test frameworks: sinon: function spy nock: mock http request supertest: test http server rewire: modify the behaviour of a module such that you can easily inject mocks and manipulate private variables More on http://www.clock.co.uk/blog/tools-for-unit-testing-and-quality-assurance-in-node-js */ var ylog = require('../'); var assert = require('should'); var chalk = require('chalk'); var _ = require('lodash'); var out = ''; var out2 = ''; ylog.__proto__.output = function(str) { out += chalk.stripColor(str); out2 += str; }; function match(target, expected, useIndexOf) { if (expected instanceof RegExp) { target.should.match(expected); } else { if (useIndexOf) { target.should.containEql(expected); target.should.not.eql(expected); } else { target.should.eql(expected); } } } function testOut(fn, strOrRe, opts) { opts = opts || {}; out = ''; out2 = ''; fn(); if (opts.trim !== false) { out = out.trim(); } out = out.replace(/[\r]/g, ''); var res = out; out = ''; if (typeof strOrRe !== 'undefined') { match(res, strOrRe, opts.useIndexOf); } return res; } function testLevel(level, text, expected) { var res = testOut(function() { ylog[level](text); }); if (level === 'silent') { res.should.eql(''); } else { if (expected) { var tag = chalk.stripColor(ylog.levels[level].tag).trim(); res.indexOf(tag).should.eql(0); res = res.replace(tag, '').trim(); } res.should.eql(expected); } } describe('ylog', function () { beforeEach(function() { out = ''; }); context('namespace', function() { it('should support debug package namespace property', function () { var y1 = ylog('y1'), y2 = ylog('y2'); y1.enabled.should.eql(false); y2.enabled.should.eql(false); // y1 and y2 are disabled testOut(function() { y1.write('y1'); y2.write('y2'); }, ''); // y1 is enabled and y2 is disabled y1.enabled = true; testOut(function() { y1.write('y1'); y2.write('y2'); }, 'y1 y1'); // y1 and y2 are enabled y2.enabled = true; testOut(function() { y1.write('y1'); y2.write('y2'); }, /y1 y1\s+y2 y2/); // y1 is disabled and y2 is enabled y1.enabled = false; testOut(function() { y1.write('y1'); y2.write('y2'); }, 'y2 y2'); }); it('should support no namespace', function() { var y = ylog; var z = ylog(); y.enabled.should.eql(true); z.enabled.should.eql(true); z.should.eql(y); testOut(function() { y.write('abc'); z.write('def'); }, /^abc\ndef$/); // you can also disable it y.enabled = false; z.enabled = false; y.write('xx'); z.write('yy'); out.should.eql(''); // recover it, because others rely on it y.enabled = true; z.enabled.should.eql(true); }); it('should support a colored namespace', function() { var y = ylog(chalk.red('hah')); y.enabled = true; testOut(function() { y.log('aa'); }); out2.should.eql('\n' + chalk.red('hah') + ' aa'); }); }); context('level', function() { var levels, first, last, second, third, forth; before(function() { levels = _.keys(ylog.levels).sort(function(a, b) { return ylog.levels[a].weight - ylog.levels[b].weight; }); first = _.first(levels); second = levels[1]; third = levels[2]; forth = levels[3]; last = _.last(levels); // 全部输出模式 ylog.setLevel(first); }); after(function() { ylog.setLevel(first); ylog.setLevelMode('weight'); }); it('should output a prefixed tag', function() { _.each(levels, function(level) { var tag = chalk.stripColor(ylog.levels[level].tag); var re = new RegExp(tag.replace(/([\[\]])/g, '\\$1') + '\\s*' + level); testOut(function() { ylog[level](level); }, level === 'silent' ? '' : re); }); }); it('should throw when set no exist level', function() { (function() { ylog.setLevel('no_exist_xx'); }).should.throw(); }); it('should support setLevelMode("weight")', function() { ylog.setLevelMode('weight'); // 当当前 level 权限高的才会输出,除了 silent ylog.setLevel(second); testLevel(first, 'will not output', ''); testLevel(second, 'output this', 'output this'); testLevel(third, 'hi', 'hi'); ylog.setLevel(third); testLevel(first, 'no', ''); testLevel(second, 'no', ''); testLevel(forth, 'yes', 'yes'); }); it('should support setLevelMode("only")', function() { ylog.setLevelMode('only'); ylog.setLevel(second); levels.forEach(function(level) { testLevel(level, level, level === second ? level : ''); }); ylog.setLevel(last); levels.forEach(function(level) { testLevel(level, level, ''); }); var g = [second, forth]; ylog.setLevel(g); levels.forEach(function(level) { testLevel(level, level, _.includes(g, level) ? level : ''); }); }); it('should support multiple levels', function() { ylog.setLevel(['ok', 'info'], 'only'); testOut(function() { ylog.ok.info('xx'); }); out2.should.eql('\n ' + ylog.levels.ok.tag + ' xx'); ylog.setLevel('silly', 'weight'); testOut(function() { ylog.info.ok('xx'); }); out2.should.eql('\n ' + ylog.levels.ok.tag + ' xx'); }); }); context('attribute', function() { it('md', function() { testOut(function() { ylog.md.log(chalk.underline('**xx**')); }, '\nxx', {trim: false}); testOut(function() { ylog.md.log('**xx** yy') }, 'xx yy'); testOut(function() { ylog.no.md.log('**xx**'); }, '**xx**'); testOut(function() { ylog.nomd.log('**xx**'); }, '**xx**'); }); it('useless no tag', function() { testOut(function() { ylog.no.log('ab'); }, 'ab'); }); it('tag', function() { testOut(function() { ylog.debug.tag.log('xx'); }, '[D] xx'); testOut(function() { ylog.debug.no.tag.log('xx'); }, '\nxx', {trim: false}); }); it('pad', function() { testOut(function() { ylog.pad(3).padChar('-').log('xx'); }, '\n---xx', {trim: false}); testOut(function() { ylog.pad(2).padChar(true).log('xx'); }, '\n xx', {trim: false}); }); it('attr', function() { testOut(function() { var a = ylog.attr({md: false, color: 'red', wrap: false}).log('ab**cd**ef'); }); out2.should.eql('\n' + chalk.red('ab**cd**ef')); }); it('eol', function() { testOut(function() { ylog.eol.ln.log('you'); }, '\n\nyou\n', {trim: false}); testOut(function() { ylog.eol('xx').ln.log('you'); }, '\n\nyou', {trim: false}); testOut(function() { ylog.eol(3).ln.log('you'); }, '\n\nyou\n\n', {trim: false}); testOut(function() { ylog.no.eol.log('are'); ylog.log('you'); }, '\nareyou', {trim: false}); }); it('color', function() { testOut(function() { ylog.no.wrap.color('red.bold').write('ab'); }); out2.should.eql('\n' + chalk.red.bold('ab')); testOut(function() { ylog.no.wrap.write('a').color('red').write('b').write('c'); }); out2.should.eql('\na ' + chalk.red('b') + ' ' + chalk.red('c')); testOut(function() { ylog.no.wrap.write('a').color('red').write('b').color('green').write('c'); }); out2.should.eql('\na ' + chalk.red('b') + ' ' + chalk.green('c')); }); it('nocolor', function() { testOut(function() { ylog.color('red').no.color.log('abc'); }); out2.should.eql('\nabc'); }); it('wrap', function() { testOut(function() { ylog.wrap(3).log('areyouok!') }, '\nare\nyou\nok!', {trim: false}); testOut(function() { ylog.wrap(3).log(chalk.red.underline('are') + chalk.green('youok!')) }, '\nare\nyou\nok!', {trim: false}); var y = ylog.wrap(0.6).log('a'); y.options.attributes.wrap.should.eql(0.6); y = ylog.wrap('60%').log('a'); y.options.attributes.wrap.should.eql('60%'); }); it('label', function() { testOut(function() { ylog.label('ab', 4).log('def'); }, 'ab def'); testOut(function() { ylog.label('ab', 4, 'right').log('def'); }, 'ab def'); testOut(function() { ylog.label('ab', 5, 'center').log('def'); }, 'ab def'); }); }); context('style', function() { it('ln', function() { testOut(function() { ylog.ln.ln.log('abc'); }, '\n\n\nabc', {trim: false}) }); it('log', function() { testOut(function() { ylog.log('abc'); }, 'abc') }); it('write', function() { testOut(function() { ylog.write('abc'); }, 'abc') }); it('title', function() { testOut(function() { ylog.title('abc'); }, 'Abc'); }); it('subtitle', function() { testOut(function() { ylog.subtitle('abc'); }, 'Abc') }); it('writeOk', function() { testOut(function() { ylog.writeOk('abc'); }, '>> abc') }); it('writeError', function() { testOut(function() { ylog.writeError('abc'); }, '>> abc') }); it('writeFlag', function() { testOut(function() { ylog.writeFlag(['a', 'b']); }, 'Flags: a, b'); testOut(function() { ylog.writeFlag({a: true, b: 'abc'}, 'XX'); }, 'XX: a, b="abc"'); testOut(function() { ylog.writeFlag(false); }, 'Flags: (none)'); }); it('align', function() { // attribute 中的 label 已经测试过此 testOut(function() { ylog.align('d'); }, 'd'); }); }); context('new flag', function() { it('create occupied flag should throw error', function() { (function() { ylog.styleFlag('namespace'); }).should.throw(); (function() { ylog.styleFlag('levels'); }).should.throw(); }); it('create exists flag should successed', function() { (function() { ylog.styleFlag('md'); }).should.not.throw(); (function() { ylog.styleFlag('tag'); }).should.not.throw(); }); it('create new level', function() { ylog.levelFlag('fuck', 4500); testOut(function() { ylog.fuck('no body'); }, 'fuck no body'); }); }); context('format output', function() { it('ylog.format', function() { // o, j, f, d, s testOut(function() { ylog.log('|%o %j %f %d %s %% %z|', {a: 1}, 'a', '1.2', '3', 'b') }, '|{ a: 1 } "a" 1.2 3 b % %z|'); testOut(function() { ylog.log(['1', 2], 1); }, /^\[ ['"]1['"], 2 \] 1$/ ); testOut(function() { ylog.log(new Error('x')); }, 'Error: x', {useIndexOf: true}); }); it('ylog.brush', function() { ylog.brush('ab', 'red.green').should.eql(chalk.red.green('ab')); (function() {ylog.brush('ab', 'red.xgreen')}).should.throw(); ylog.brush('ab', '').should.eql('ab'); }); }); context('config', function() { before(function() { ylog.attributes.nsPad = 3; }); after(function() { ylog.attributes.nsPad = 0; }); it('disable some markdown', function() { ylog.markdowns['**'] = false; testOut(function() { ylog.log('**xx**'); }, '**xx**'); ylog.markdowns['**'] = true; }); it('hide ns tag', function() { ylog.Tag.ns.show = false; var y = ylog('ab'); y.enabled = true; testOut(function() { y.log('xx'); }, 'xx'); ylog.Tag.ns.show = true; }); it('show pid tag', function() { ylog.Tag.pid.show = true; testOut(function() { ylog.log('xx'); }, /^\d+ xx$/); ylog.Tag.pid.show = false; }); it('ns tag align', function() { var ab = ylog('ab'); var abc = ylog('abc'); ab.enabled = true; abc.enabled = true; testOut(function() { ylog.Tag.ns.align = 'left'; ylog.Tag.ns.len = 4; ab.log('ab'); abc.log('bc'); }, '\n ab ab\n abc bc', {trim: false}); testOut(function() { ylog.Tag.ns.align = 'right'; ylog.Tag.ns.len = 4; ab.log('ab'); abc.log('bc'); }, '\n ab ab\n abc bc', {trim: false}); ylog.Tag.ns.len = 0; }); it('re-order ns and level tag', function() { ylog.Tag.ns.order = 40; testOut(function() { var y = ylog('y'); y.enabled = true; y.debug('c'); }, '[D] y c'); ylog.Tag.ns.order = 20; }); it('prefixLabelEachLine', function() { ylog.attributes.prefix = true; testOut(function() { var y = ylog('ab'); y.enabled = true; y.wrap(3).log('areyouok!'); }, '\n ab are\n ab you\n ab ok!', {trim: false}); ylog.attributes.prefix = false; }); }); context('event', function() { it('should emit sys.[ns].[level]', function() { var a = 0; var y = ylog('ab'); y.enabled = true; ylog.on('ab.ok', function() { a++; }); y.ok(1); y.ok(2); y.error(2); y.debug(2); a.should.eql(2); }); }); context('chain', function() { it('chain remain first level info', function() { ylog.setLevel('debug'); testOut(function() { ylog.verbose('xx').ln.log('yy'); }, '', {trim: false, useIndexOf: false}); }); }); });