/*global describe, it*/ "use strict"; var gulp = require('gulp'), should = require('should'), through = require('through2'), plumber = require('gulp-plumber'), PluginError = require('plugin-error'), Vinyl = require('vinyl'), join = require('path').join, fs = require('fs'), notify = require('../'); var mockGenerator = function (tester) { tester = tester || function () { }; return function (opts, callback) { tester(opts); callback(); }; }; var originalLogger = notify.logger(); describe('gulp output stream', function() { beforeEach(function () { notify.logLevel(0); notify.logger(originalLogger); }); describe('notify()', function() { it('should return a stream', function(done) { var stream = notify({ notifier: mockGenerator() }); should.exist(stream); should.exist(stream.on); should.exist(stream.pipe); done(); }); it('should allow setting of own reporter', function(done) { var notifier = notify.withReporter(mockGenerator); var stream = notifier(); should.exist(stream); should.exist(stream.on); should.exist(stream.pipe); done(); }); it('should set message, title and have default icon of Gulp logo', function(done) { var testString = "this is a test"; var expectedIcon = join(__dirname, '..', 'assets', 'gulp.png'); var expectedFile = new Vinyl({ path: "test/fixtures/1.txt", cwd: "test/", base: "test/fixtures/", contents: fs.createReadStream("test/fixtures/1.txt") }); var mockedNotify = notify.withReporter(mockGenerator(function (opts) { opts.should.have.property('title'); opts.should.have.property('message'); opts.should.have.property('icon'); String(opts.icon).should.equal(expectedIcon); String(opts.message).should.equal(testString); done(); }.bind(this))); var outstream = mockedNotify({ message: testString }); outstream.write(expectedFile); }); it('should be able to override default icon', function(done) { var testString = "this is a test"; var expectedIcon = "testIcon"; var expectedFile = new Vinyl({ path: "test/fixtures/1.txt", cwd: "test/", base: "test/fixtures/", contents: fs.createReadStream("test/fixtures/1.txt") }); var mockedNotify = notify.withReporter(mockGenerator(function (opts) { opts.should.have.property('title'); opts.should.have.property('message'); opts.should.have.property('icon'); String(opts.icon).should.equal(expectedIcon); String(opts.message).should.equal(testString); done(); }.bind(this))); var outstream = mockedNotify({ message: testString, icon: expectedIcon }); outstream.write(expectedFile); }); it('should call notifier with extra options untouched', function(done) { var testString = "this is a test"; var testIcon = "face-cool"; var mockedNotify = notify.withReporter(mockGenerator(function (opts) { should.exist(opts); should.exist(opts.icon); should.exist(opts.message); String(opts.icon).should.equal(testIcon); String(opts.message).should.equal(testString); })); var instream = gulp.src(join(__dirname, "./fixtures/*.txt")), outstream = mockedNotify({ message: testString, icon: testIcon }); outstream.on('data', function(file) { should.exist(file); should.exist(file.path); should.exist(file.contents); }); outstream.on('end', function() { done(); }); instream.pipe(outstream); }); it('should emit error when sub-module returns error and emitError is true', function(done) { var mockedNotify = notify.withReporter(function (options, callback) { callback(new Error(testString)); }); var testString = "testString", instream = gulp.src(join(__dirname, "./fixtures/*.txt")), outstream = mockedNotify({ message: testString, emitError: true }); outstream.on('error', function (error) { should.exist(error); should.exist(error.message); String(error.message).should.equal(testString); done(); }); instream.pipe(outstream); }); it('should pass on files', function(done) { var mockedNotify = notify.withReporter(mockGenerator()); var testSuffix = "tester", srcFile = join(__dirname, "./fixtures/*"), instream = gulp.src(srcFile), outstream = mockedNotify(); var numFilesBefore = 0, numFilesAfter = 0; instream .pipe(through.obj(function (file, enc, cb) { numFilesBefore++; this.push(file); cb(); }, function (cb) { numFilesBefore.should.equal(3); cb(); })) .pipe(outstream) .pipe(through.obj(function (file, enc, cb) { numFilesAfter++; this.push(file); cb(); }, function (callback) { numFilesAfter.should.equal(3); done(); })); }); it('should pass on files even on error in notifier (with use of plumber)', function(done) { var testString = "tester", srcFile = join(__dirname, "./fixtures/*"), instream = gulp.src(srcFile), outstream = notify({ notifier: function (options, callback) { callback(new Error(testString)); } }); var numFilesBefore = 0, numFilesAfter = 0; instream .pipe(plumber()) .pipe(through.obj(function (file, enc, cb) { numFilesBefore++; this.push(file); cb(); }, function (cb) { numFilesBefore.should.equal(3); cb(); })) .pipe(outstream) .on('error', function (error) { error.message.should.equal(testString); }) .pipe(through.obj(function (file, enc, cb) { numFilesAfter++; this.push(file); cb(); }, function (callback) { numFilesAfter.should.equal(3); done(); })); }); it('should emit error when sub-module throws exception/error and emitError flag is true', function(done) { var testString = "some exception", instream = gulp.src(join(__dirname, "./fixtures/*.txt")), outstream = notify({ message: testString, notifier: function (options, callback) { throw new Error(testString); }, emitError: true }); outstream.on('error', function (error) { should.exist(error); should.exist(error.message); String(error.message).should.equal(testString); done(); }); instream.pipe(outstream); }); it('should not emit error when sub-module throws exception/error if emitError flag is false (default)', function(done) { notify.logLevel(1); notify.logger(function () { should.exist(true); done(); }); var testString = "some exception", expectedFile = new Vinyl({ path: "test/fixtures/1.txt", cwd: "test/", base: "test/fixtures/", contents: fs.createReadStream("test/fixtures/1.txt") }), outstream = notify({ message: testString, notifier: function (options, callback) { throw new Error(testString); } }); outstream.on('error', function (error) { should.not.exist(error); should.not.exist(error.message); String(error.message).should.not.equal(testString); done(); }); outstream.on('end', function () { done(); }); outstream.write(expectedFile); outstream.write(null); outstream.end(); }); it('should default to notifying file path and default title', function(done) { var srcFile = join(__dirname, "./fixtures/1.txt"); var instream = gulp.src(srcFile), outstream = notify({ notifier: mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); String(opts.message).should.equal(srcFile); String(opts.title).should.equal("Gulp notification"); }) }); outstream.on('data', function(file) { should.exist(file); should.exist(file.path); should.exist(file.contents); }); outstream.on('end', function() { done(); }); instream.pipe(outstream); }); it('should take function with file as argument, as message or title', function(done) { var testSuffix = "tester", srcFile = join(__dirname, "./fixtures/1.txt"), instream = gulp.src(srcFile), outstream = notify({ notifier: mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); String(opts.message).should.equal(srcFile + testSuffix); String(opts.title).should.equal(srcFile + testSuffix); }), message: function (file) { String(file.path).should.equal(srcFile); return file.path + testSuffix; }, title: function (file) { String(file.path).should.equal(srcFile); return file.path + testSuffix; } }); outstream.on('data', function(file) { should.exist(file); should.exist(file.path); should.exist(file.contents); }); outstream.on('end', function() { done(); }); instream.pipe(outstream); }); it('should notify on all files per default', function(done) { var testSuffix = "tester", srcFile = join(__dirname, "./fixtures/*"), instream = gulp.src(srcFile), numFunctionCalls = 0, outstream = notify({ notifier: mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); numFunctionCalls++; }) }); outstream.on('data', function(file) { should.exist(file); should.exist(file.path); should.exist(file.contents); }); outstream.on('end', function() { numFunctionCalls.should.equal(3); done(); }); instream.pipe(outstream) }); it('should handle streamed files', function (done) { var expectedFile = new Vinyl({ path: "test/fixtures/1.txt", cwd: "test/", base: "test/fixtures/", contents: fs.createReadStream("test/fixtures/1.txt") }); var testString = "testString"; var outstream = notify({ message: testString, notifier: mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); String(opts.message).should.equal(testString); }) }); outstream.on('error', function (err) { should.not.exist(err); }); outstream.on('data', function(file) { should.exist(file); should.exist(file.isStream()); should.exist(file.path); should.exist(file.contents); done(); }); outstream.write(expectedFile); }); it('should support lodash template for titles and messages', function (done) { var expectedFile = new Vinyl({ path: "test/fixtures/1.txt", cwd: "test/", base: "test/fixtures/", contents: fs.createReadStream("test/fixtures/1.txt") }); var testString = "Template: <%= file.relative %>"; var expectedString = "Template: 1.txt"; var outstream = notify({ message: testString, title: testString, notifier: mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); String(opts.message).should.equal(expectedString); String(opts.title).should.equal(expectedString); }) }); outstream.on('error', function (err) { should.not.exist(err); }); outstream.on('data', function(file) { should.exist(file); should.exist(file.path); should.exist(file.contents); done(); }); outstream.write(expectedFile); }); }); describe('notify.onLast', function() { it('should only notify on the last file, if onLast flag is activated', function(done) { var testSuffix = "tester", srcFile = join(__dirname, "./fixtures/*"), instream = gulp.src(srcFile), numFunctionCalls = 0, outstream = notify({ onLast: true, notifier: mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); numFunctionCalls++; }) }); outstream.on('data', function(file) { should.exist(file); should.exist(file.path); should.exist(file.contents); }); outstream.on('end', function() { numFunctionCalls.should.equal(1); done(); }); instream.pipe(outstream); }); it('should stream all files even if onLast is activated', function(done) { var testSuffix = "tester", srcFile = join(__dirname, "./fixtures/*"), instream = gulp.src(srcFile), outstream = notify({ onLast: true, notifier: mockGenerator() }); var numFilesBefore = 0, numFilesAfter = 0; instream .pipe(through.obj(function (file, enc, cb) { numFilesBefore++; this.push(file); cb(); }, function (cb) { numFilesBefore.should.equal(3); cb(); })) .pipe(outstream) .pipe(through.obj(function (file, enc, cb) { numFilesAfter++; this.push(file); cb(); }, function (callback) { numFilesAfter.should.equal(3); done(); })); }); it('should support lodash template for titles and messages when onLast', function (done) { var testSuffix = "tester", srcFile = join(__dirname, "./fixtures/*"), instream = gulp.src(srcFile), numFunctionCalls = 0, outstream = notify({ onLast: true, message: 'Template: <%= file.relative %>', notifier: mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); opts.message.should.startWith('Template:') opts.message.should.endWith('.txt') numFunctionCalls++; }) }); outstream.on('data', function(file) { should.exist(file); should.exist(file.path); should.exist(file.contents); }); outstream.on('end', function() { numFunctionCalls.should.equal(1); done(); }); instream.pipe(outstream); }); }); describe('notify.logger()', function() { it('should allow setting of logLevel', function(done) { var notifier = notify.withReporter(mockGenerator); should.exist(notify.logLevel); should.exist(notify.logger); done(); }); it('should log error on log level 1', function(done) { var srcFile = join(__dirname, "./fixtures/1.txt"); notify.logLevel(1); notify.logger(function (options) { should.exist(true); done(); }); var notifier = notify.withReporter(mockGenerator); gulp.src(srcFile) .pipe(through.obj(function (file, enc, cb) { this.emit("error", new PluginError("testPlugin", "foo")); cb(); })) .on("error", notifier.onError()) }); it('should not log on log level 0', function(done) { var srcFile = join(__dirname, "./fixtures/1.txt"); var hasBeenCalled = false; notify.logLevel(0); notify.logger(function () { hasBeenCalled = true; should.not.exist(arguments); }); var notifier = notify.withReporter(mockGenerator(function () { should(hasBeenCalled).equal(false); done(); })); gulp.src(srcFile) .pipe(through.obj(function (file, enc, cb) { this.emit("error", new PluginError("testPlugin", "foo")); cb(); })) .on("error", notifier.onError()) }); }); describe('notify.onError()', function() { it('should have defined onError function on object', function (done) { should.exist(notify.onError); done(); }); it('should have onError event withReporter', function(done) { var notifier = notify.withReporter(mockGenerator); should.exist(notifier.onError); done(); }); it('should call end on stream', function (done) { var onError = notify.onError({ notifier: mockGenerator(function (opts) { }) }); var stream = through.obj(function (file, enc, cb) { this.emit('error', 'error'); cb(); }); stream.on('error', onError).on('end', done); stream.write({}); }); it('should be limited by notifying on error if th onError-option is passed', function (done) { var testMessage = "tester", srcFile = join(__dirname, "./fixtures/*"), onError = notify.onError({ notifier: mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); String(opts.message).should.equal(testMessage); String(opts.title).should.equal("Error running Gulp"); done(); }) }); gulp.src(srcFile) .pipe(through.obj(function (file, enc, cb) { this.emit("error", new PluginError("testPlugin", testMessage)); cb(); })) .on("error", onError) }); it('should have onError options on withReporter sugar', function (done) { var testMessage = "tester", srcFile = join(__dirname, "./fixtures/*"); var custom = notify.withReporter(mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); String(opts.message).should.equal(testMessage); String(opts.title).should.equal("Error running Gulp"); done(); })); gulp.src(srcFile) .pipe(through.obj(function (file, enc, cb) { this.emit("error", new PluginError("testPlugin", testMessage)); cb(); })) .on("error", custom.onError()) }); it('should have default Gulp-error logo onError', function (done) { var expectedIcon = join(__dirname, '..', 'assets', 'gulp-error.png'); var testMessage = "tester", srcFile = join(__dirname, "./fixtures/*"); var custom = notify.withReporter(mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); should.exist(opts.icon); String(opts.message).should.equal(testMessage); String(opts.icon).should.equal(expectedIcon); String(opts.title).should.equal("Error running Gulp"); done(); })); gulp.src(srcFile) .pipe(through.obj(function (file, enc, cb) { this.emit("error", new PluginError("testPlugin", testMessage)); cb(); })) .on("error", custom.onError()) }); it('should be able to override default icon onError', function (done) { var expectedIcon = "testIcon"; var testMessage = "tester"; var custom = notify.withReporter(mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); should.exist(opts.icon); String(opts.message).should.equal(testMessage); String(opts.icon).should.equal(expectedIcon); String(opts.title).should.equal("Error running Gulp"); done(); })); custom.onError({ icon: expectedIcon, })(new PluginError("testPlugin", testMessage)); }); it('should have Frog sound per default onError', function (done) { var expectedIcon = "testIcon"; var testMessage = "tester"; var custom = notify.withReporter(mockGenerator(function (opts) { should.exist(opts); should.exist(opts.sound); String(opts.sound).should.equal('Frog'); done(); })); custom.onError({ icon: expectedIcon, })(new PluginError("testPlugin", testMessage)); }); it('should support lodash template for titles and messages on onError', function (done) { var testString = "Template: <%= error.message %>"; var expectedString = "Template: test"; var srcFile = join(__dirname, "./fixtures/*"); var onError = notify.onError({ message: testString, title: testString, notifier: mockGenerator(function (opts) { should.exist(opts); should.exist(opts.title); should.exist(opts.message); String(opts.message).should.equal(expectedString); String(opts.title).should.equal(expectedString); done(); }) }); gulp.src(srcFile) .pipe(through.obj(function (file, enc, cb) { this.emit("error", new PluginError("testPlugin", "test")); cb(); })) .on('error', onError); }); }); });