diff --git a/CHANGELOG.md b/CHANGELOG.md index 31224c1..44e1d4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ The changelog for BOKOR includes information about the each release including any update notes, release notes as well as bug fixes, updates to existing features and new features. +--- +## 2.0.0 + +### Release Notes +#### Added + +- Migrated logging to Bunyan - thanks! [Erik Sutherland](https://github.com/MrRacoon) +- Replaced deprecated istanbul with nyc for code coverage +- Updated dependencies for security + --- ## 1.3.3 diff --git a/README.md b/README.md index 30cd0ed..c5cb858 100644 --- a/README.md +++ b/README.md @@ -287,13 +287,16 @@ bokorServer/ ``` ## Logs -`====[ cache miss ]====` +Bokor uses [Bunyan](https://github.com/trentm/node-bunyan) for logging. Bunyan is a simple and fast JSON logging library. +Bunyan has many features. One of them allows pretty-printing of the log. We show this feature in the below [Demo From Source](#demo-from-source) -❤️ If the request does not find a prerecorded response it will log cache miss in the color red. +`(cache=miss)` -`====[ cache hit ]====` +❤️ If the request does not find a prerecorded response it will log cache miss. -💚 If the request finds a prerecorded response it will log cache hit in the color green. +`(cache=hit)` + +💚 If the request finds a prerecorded response it will log cache hit. ## Demo from Source Follow the below steps to run the Bokor Demo. @@ -303,7 +306,7 @@ $ git clone https://github.com/Nike-Inc/bokor.git $ cd bokor $ npm install $ cd examples/source_example/ -$ node server.js +$ node server.js | ../../node_modules/.bin/bunyan ``` Record a response @@ -320,20 +323,20 @@ $ curl http://localhost:7777/users/jimmyeisenhauer ## Tests ``` -$ npm test +$ npm run coverage ``` ## FAQ ### Where did the name Bokor come from? It is a long story, but one of my favorite quotes is: -#####“any sufficiently advanced technology is indistinguishable from magic.” +##### “any sufficiently advanced technology is indistinguishable from magic.” -arthur c. clarke So of course I penned a similar quote around test automation. -#####“software tests that unexplainably pass or fail are indistinguishable from voodoo.” +##### “software tests that unexplainably pass or fail are indistinguishable from voodoo.” -james r. eisenhauer And a Bokor is a voodoo sorcerer for hire who are said to serve the loa 'with both hands', practicing for both good and evil. diff --git a/lib/bokor.js b/lib/bokor.js index 5497a60..37d6fc0 100644 --- a/lib/bokor.js +++ b/lib/bokor.js @@ -20,22 +20,31 @@ var bokorOptions = {}; require('colors'); require('http'); +function start(options) { + // -- sepia config -------------- + // default bokor admin server on by default + var sepia; + if (options.admin === false) { + sepia = require('./sepia'); + } else { + sepia = require('./sepia').withSepiaServer(); + } -function start(options) { + var logger = sepia.logger; // -- bokor config -------------- if (options.servers != null) { bokorOptions.servers = options.servers; } else { - console.log('CONFIGURATION ERROR: Missing server config'.red); + logger.error('CONFIGURATION ERROR: Missing server config'); return; } if (options.filters != null) { bokorOptions.filters = options.filters; } else { - console.log('CONFIGURATION ERROR: Missing filters config'.red); + logger.error('CONFIGURATION ERROR: Missing filters config'); return; } @@ -43,14 +52,6 @@ function start(options) { bokorOptions.staticFileLocation = options.staticFileLocation || 'static_files'; // bokor server static file location bokorOptions.secure = options.secure === undefined ? true : false; - // -- sepia config -------------- - // default bokor admin server on by default - var sepia; - if (options.admin === false) { - sepia = require('./sepia'); - } else { - sepia = require('./sepia').withSepiaServer(); - } sepia.configure({ verbose: true, @@ -120,8 +121,8 @@ function start(options) { host: serverConfig.url } }, function(e) { - console.log('[ERROR] proxying to endpoint: '.red + serverConfig.url); - console.log(e); + logger.error({ url: serverConfig.url }, 'proxying to endpoint'); + logger.error({ err: e }); res.send(JSON.stringify({ bokorProxyError: 1 })); }); }); @@ -131,7 +132,7 @@ function start(options) { return new Promise(function (resolve) { server.listen(server.get('port'), function() { - console.log('bokor'.red + ' server'.blue + ' rolled '.green.bold + 'lucky '.blue + server.get('port')); + logger.info({ port: server.get('port') }, 'bokor listening'); resolve(server); }); }); diff --git a/lib/sepia/README.md b/lib/sepia/README.md index 764da22..a9c1331 100644 --- a/lib/sepia/README.md +++ b/lib/sepia/README.md @@ -1,11 +1,6 @@ # This is a heavily modified version of sepia for bokor # Thanks linkedin for the inspiration and code! - - - - - # sepia - the way things used to be Sepia is a VCR-like module for node.js that records HTTP interactions, then diff --git a/lib/sepia/index.js b/lib/sepia/index.js index a922b1d..1eb5ebc 100644 --- a/lib/sepia/index.js +++ b/lib/sepia/index.js @@ -59,6 +59,7 @@ function shutdown(next) { } var sepiaUtil = require('./src/util'); +module.exports.logger = sepiaUtil.internal.log; module.exports.filter = sepiaUtil.addFilter; module.exports.substitute = sepiaUtil.addSubstitution; module.exports.fixtureDir = sepiaUtil.setFixtureDir; diff --git a/lib/sepia/src/logger.js b/lib/sepia/src/logger.js new file mode 100644 index 0000000..889f41e --- /dev/null +++ b/lib/sepia/src/logger.js @@ -0,0 +1,7 @@ +var bunyan = require('bunyan'); + +const logger = bunyan.createLogger({ + name: 'bokor', +}); + +module.exports = logger; diff --git a/lib/sepia/src/util.js b/lib/sepia/src/util.js index e4d311b..0643700 100644 --- a/lib/sepia/src/util.js +++ b/lib/sepia/src/util.js @@ -17,13 +17,9 @@ var url = require('url'); var path = require('path'); var crypto = require('crypto'); var fs = require('fs'); +var logger = require('./logger'); var Levenshtein = require('levenshtein'); -const COLOR_RESET = '\033[0m'; -const COLOR_RED_BOLD = '\033[1;31m'; -const COLOR_GREEN_BOLD = '\033[1;32m'; -const COLOR_BLUE_BOLD = '\033[1;34m'; - // -- GLOBAL STATE HANDLING ---------------------------------------------------- var globalOptions = {}; @@ -220,18 +216,6 @@ function usesGlobalFixtures(reqUrl) { // -- LOGGING ------------------------------------------------------------------ -function log(color, args) { - if (!globalOptions.verbose) { - return; - } - - var args = Array.prototype.slice.call(args); - args.unshift(color); - args.push(COLOR_RESET); - - console.log.apply(console, args); -} - function logFixtureStatus(filename, filenameParts) { if (!globalOptions.verbose) { return; @@ -240,19 +224,17 @@ function logFixtureStatus(filename, filenameParts) { filename = filename + '.headers'; if (fs.existsSync(filename)) { - log(COLOR_GREEN_BOLD, [ - '\n ====[ cache hit ]====\n', - filenameParts, '\n', - 'filename:', filename, '\n', - '======================\n' - ]); + logger.info({ + cache: 'hit', + filenameParts: filenameParts, + filename: filename, + }); } else { - log(COLOR_RED_BOLD, [ - '\n ====[ cache miss ]====\n', - filenameParts, '\n', - 'filename:', filename, '\n', - '======================\n' - ]); + logger.info({ + cache: 'miss', + filenameParts: filenameParts, + filename: filename, + }); } } @@ -262,13 +244,11 @@ function logFixtureDebugStatus(filename, bestMatchingFixture, fileHash) { } // Print the hashParts - log(COLOR_BLUE_BOLD, [ - '\n ==== Best matching Fixture ====\n', - 'to :', filename, '\n', - 'filename:', bestMatchingFixture, '\n\n', - 'hashParts:', fileHash, '\n', - '======================\n' - ]); + logger.info({ + to: filename, + filename: bestMatchingFixture, + hashParts: fileHash, + }); } // -- FILENAME CONSTRUCTION ---------------------------------------------------- @@ -476,7 +456,7 @@ module.exports.internal.mkdirpSync = mkdirpSync; module.exports.internal.filterByWhitelist = filterByWhitelist; module.exports.internal.usesGlobalFixtures = usesGlobalFixtures; module.exports.internal.touchOnHit = touchOnHit; -module.exports.internal.log = log; +module.exports.internal.log = logger; module.exports.internal.logFixtureStatus = logFixtureStatus; module.exports.internal.logFixtureDebugStatus = logFixtureDebugStatus; module.exports.internal.parseCookiesNames = parseCookiesNames; diff --git a/package-lock.json b/package-lock.json index b93b954..127fef4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -262,8 +262,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -295,7 +294,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -313,6 +311,17 @@ "integrity": "sha1-h/yqOimDWOCt5uRCz86EB0DRrQQ=", "dev": true }, + "bunyan": { + "version": "1.8.12", + "resolved": "https://artifactory.palantir.build/artifactory/api/npm/all-npm/bunyan/-/bunyan-1.8.12.tgz", + "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -451,8 +460,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", @@ -674,6 +682,15 @@ "domelementtype": "1" } }, + "dtrace-provider": { + "version": "0.8.7", + "resolved": "https://artifactory.palantir.build/artifactory/api/npm/all-npm/dtrace-provider/-/dtrace-provider-0.8.7.tgz", + "integrity": "sha1-3JObTT4GIM/gwc2APQ0tftBP/QQ=", + "optional": true, + "requires": { + "nan": "^2.10.0" + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -940,6 +957,20 @@ "assert-plus": "^1.0.0" } }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -1092,7 +1123,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1244,6 +1274,15 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -1476,7 +1515,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -1491,7 +1529,6 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" }, @@ -1499,8 +1536,7 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } }, @@ -1573,6 +1609,29 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "mv": { + "version": "2.1.1", + "resolved": "https://artifactory.palantir.build/artifactory/api/npm/all-npm/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + } + }, + "nan": { + "version": "2.14.0", + "resolved": "https://artifactory.palantir.build/artifactory/api/npm/all-npm/nan/-/nan-2.14.0.tgz", + "integrity": "sha1-eBj3IgJ7JFmobwKV1DTR/CM2xSw=", + "optional": true + }, + "ncp": { + "version": "2.0.0", + "resolved": "https://artifactory.palantir.build/artifactory/api/npm/all-npm/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "optional": true + }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", @@ -1664,6 +1723,15 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } } } }, @@ -1685,7 +1753,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -1784,8 +1851,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-parse": { "version": "1.0.6", @@ -2051,24 +2117,23 @@ "dev": true }, "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, + "version": "2.4.5", + "resolved": "https://artifactory.palantir.build/artifactory/api/npm/all-npm/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "optional": true, "requires": { - "glob": "^7.1.3" + "glob": "^6.0.1" }, "dependencies": { "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, + "version": "6.0.4", + "resolved": "https://artifactory.palantir.build/artifactory/api/npm/all-npm/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, "requires": { - "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "2 || 3", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -2080,6 +2145,12 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://artifactory.palantir.build/artifactory/api/npm/all-npm/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha1-NW5EvJjx+TzkXfFLzXwBzahuCv0=", + "optional": true + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2236,6 +2307,17 @@ "rimraf": "^2.6.2", "signal-exit": "^3.0.2", "which": "^1.3.0" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "spdx-correct": { @@ -2561,8 +2643,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "2.4.3", diff --git a/package.json b/package.json index f4c9057..c5bcc6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bokor", - "version": "1.3.3", + "version": "2.0.0", "description": "Bokor is a simple, Record and Playback Mock Server written in Node.js, utilized for Service Virtualization.", "main": "index.js", "scripts": { @@ -39,6 +39,7 @@ "then-request": "^2.2.0" }, "dependencies": { + "bunyan": "^1.8.12", "colors": "^1.1.2", "express": "^4.14.0", "http-proxy": "^1.15.2", diff --git a/test/util.js b/test/util.js index 47d2941..f712c2b 100644 --- a/test/util.js +++ b/test/util.js @@ -374,119 +374,6 @@ describe('util.js', function() { }); }); - describe('#log', function() { - const log = util.internal.log; - - beforeEach(function() { - sinon.stub(console, 'log'); // console.log becomes a noop - }); - - afterEach(function() { - console.log.restore(); - }); - - it('logs the given message in the given color', function() { - util.configure({ verbose: true }); - - log('\033[31m', ['arg1', 'arg2']); - console.log.calledWithExactly('\033[31m', 'arg1', 'arg2', '\033[0m') - .should.equal(true); - }); - - it('does not log anything if in non-verbose mode', function() { - util.configure({ verbose: false }); - - log('\033[31m', 'arg1', 'arg2'); - console.log.called.should.equal(false); - }); - }); - - describe('#logFixtureStatus', function() { - const logFixtureStatus = util.internal.logFixtureStatus; - - beforeEach(function() { - sinon.stub(console, 'log'); // console.log becomes a noop - }); - - afterEach(function() { - console.log.restore(); - fs.existsSync.restore(); - }); - - it('logs a cache hit if the fixture exists', function() { - util.configure({ verbose: true }); - sinon.stub(fs, 'existsSync').returns(false); - fs.existsSync.withArgs('my-filename.headers').returns(true); - - logFixtureStatus('my-filename', 'my-hash-body'); - console.log.calledOnce.should.equal(true); - console.log.args[0][0].should.equal('\033[1;32m'); - console.log.args[0][1].should.containEql('cache hit'); - console.log.args[0].should.containEql('my-filename.headers'); - console.log.args[0].should.containEql('my-hash-body'); - }); - - it('logs a cache miss if the fixture does not exist', function() { - util.configure({ verbose: true }); - sinon.stub(fs, 'existsSync').returns(true); - fs.existsSync.withArgs('my-filename.headers').returns(false); - - logFixtureStatus('my-filename', 'my-hash-body'); - console.log.calledOnce.should.equal(true); - console.log.args[0][0].should.equal('\033[1;31m'); - console.log.args[0][1].should.containEql('cache miss'); - console.log.args[0].should.containEql('my-filename.headers'); - console.log.args[0].should.containEql('my-hash-body'); - }); - - it('does not log anything if in non-verbose mode', function() { - util.configure({ verbose: false }); - sinon.stub(fs, 'existsSync').returns(true); - - logFixtureStatus('filename', 'my-hash-body'); - fs.existsSync.called.should.equal(false); - console.log.called.should.equal(false); - }); - }); - - describe('#logFixtureDebugStatus', function() { - const logFixtureDebugStatus = util.internal.logFixtureDebugStatus; - - beforeEach(function() { - sinon.stub(console, 'log'); // console.log becomes a noop - }); - - afterEach(function() { - console.log.restore(); - fs.existsSync.restore(); - }); - - it('does not log anything if in non-verbose mode', function() { - util.configure({ verbose: false }); - sinon.stub(fs, 'existsSync').returns(true); - - logFixtureDebugStatus('my-missing-filename', 'my-best-matching-fixture', - 'my-best-matching-fixture-file-hash'); - fs.existsSync.called.should.equal(false); - console.log.called.should.equal(false); - }); - - it('logs a best matching fixture when verbose mode is true', function() { - util.configure({ verbose: true }); - sinon.stub(fs, 'existsSync').returns(true); - fs.existsSync.withArgs('my-filename.headers').returns(false); - - logFixtureDebugStatus('my-missing-filename', 'my-best-matching-fixture', - 'my-best-matching-fixture-file-hash'); - console.log.calledOnce.should.equal(true); - console.log.args[0][0].should.equal('\033[1;34m'); - console.log.args[0][1].should.containEql('==== Best matching Fixture ===='); - console.log.args[0].should.containEql('my-missing-filename'); - console.log.args[0].should.containEql('my-best-matching-fixture'); - console.log.args[0].should.containEql('my-best-matching-fixture-file-hash'); - }); - }); - describe('#parseCookiesNames', function() { const parseCookiesNames = util.internal.parseCookiesNames;