Muting stdout and stderr during Mocha tests - node.js

I'll preface this by admitting that I'm probably doing something I shouldn't be doing. But since I'm already this deep, I might as well understand why things are happening this way.
I am using Mocha to test some Node.js code. This code uses the Winston logging library, which directly calls process.stdout.write() and process.stderr.write() (source). It works well; I have no complaints about that behavior.
However, when I unit-test this code, the output of the Mocha test runner is occasionally interspersed with lines of log output, which is ugly in some reporters (dot, bdd) and downright invalid in others (xunit). I wanted to block this output without modifying or subclassing Winston, and I wanted to avoid modifying the application itself if I could avoid it.
What I arrived at was a set of utility functions that can temporarily replace the Node builtins with a no-op function, and vice versa:
var stdout_write = process.stdout._write,
stderr_write = process.stderr._write;
function mute() {
process.stderr._write = process.stdout._write = function(chunk, encoding, callback) {
callback();
};
}
function unmute() {
process.stdout._write = stdout_write;
process.stderr._write = stderr_write;
}
Inside the various test specs, I called mute() directly before any call or assertion that produced unwanted output, and unmute() directly after. It felt a little hacky, but it worked -- not a single byte of unwanted output appeared on the console when running the tests.
Now it gets weird!
For the first time, I tried redirecting the output to a file:
mocha spec_file.js > output.txt
The unwanted output came back! Every piece of output that was sent to stdout appears in the file. Adding 2>&1, I get stderr in the file too. Nothing appears on the console in either case, though.
Why would the test code behave so differently between the two invocations? My gut guess is that Mocha is doing some sort of test to determine whether or not it's writing to a TTY, but I couldn't spot an obvious place where it changes the behavior of its writes.
Also the broader question, is there any correct way to mute stdout/stderr during tests, without wrapping all potentially-logging app code in a conditional that checks for the test environment?

See https://www.npmjs.org/package/mute
it('should shut the heck up', function (done) {
var unmute = mute()
app.options.defaults = true;
app.run(function() {
unmute();
helpers.assertFiles([
['package.json', /"name": "temp-directory"/],
['README.md', /# TEMP.Directory/]
]);
done();
});
});

I discovered a likely cause for this behavior. It does indeed have to do with whether or not stdout/stderr is a TTY.
When the script runs in a console, these are both TTYs, and process.stdout and process.stderr appear to be instances of tty.WriteStream and not, as I originally assumed, a stream.Writable. As far as my interactions went, the two classes really weren't that different -- both had public write() methods which called internal _write() methods, and both shared the same method signatures.
When piped to a file, things got a little different. process.stdout and process.stderr were instances of a different class that wasn't immediately familiar. Best I can figure, it's a fs. SyncWriteStream, but that's a stab in the dark. Anyway, this class doesn't have a _write() method, so trying to override it was pointless.
The solution was to move one level higher and do my muting with write() instead of _write(). It does the same thing, and it does it consistently regardless of where the output is going.

Related

how to suppress output of a function in node/typescript

I have a typescript/node application where I am calling a 3rd-party function from a package that will output a string to the console. However, I want to know if it is possible to somehow suppress any kind of output (to the console/terminal) that this function will produce. I know that adding console.log = () => {} at the top of the file can do the job, but the linting rules (which I cannot change) of my group project state that calls to console.log are not allowed. Would anyone know of a more effective way of disabling output to console, without actually making reference to console?

Find out what file is requiring another file in Node

The title says pretty much what I need to do.
I have a module in node_modules which prints something to the standard output (and I don't want this to happen) but I don't find where I'm requiring this file.
I may be misunderstanding how modules are included, as I though that they must be required in order to be executed.
There are multiple ways for stuff to write to output. If it's just using console.log(), just swap in trace. Before your require() statements:
console.log = console.trace;
Then, you'll have the full trace output every time there's a log.
Using this console.log mod :
let old = console.log;
console.log = function(){
return old.apply(this,[].slice.apply(arguments).concat([(new Error()).stack.split(/\n/)[2].trim()]));
}
If you try :
console.log('I am trackable!')
You will get as output :
I am trackable! at test (/path/solution.js:5:9)
Happy hunting!

How to statically analyse that a file is fit for importing?

I have CLI program that can be executed with a list of files that describe instructions, e.g.
node ./my-program.js ./instruction-1.js ./instruction-2.js ./instruction-3.js
This is how I am importing and validating that the target file is an instruction file:
const requireInstruction = (instructionFilePath) => {
const instruction = require(instructionFilePath)
if (!instruction.getInstruction) {
throw new Error('Not instruction file.');
}
return instruction;
};
The problem with this approach is that it will execute the file executes regardless of whether it matches the expected signature, i.e. if file contains a side action such as connecting to the database:
const mysql = require('mysql');
mysql.createConnection(..);
module.exports = mysql;
Not instruction file. will fire, I will ignore the file, but the side-action will remain in the background.
How to safely validate target file signature?
Worst case scenario, is there a conventional way to completely sandbox the require logic and kill the process if file is determined to be unsafe?
Worst case scenario, is there a conventional way to completely sandbox the require logic and kill the process if file is determined to be unsafe?
Move the check logic into a specific js file. Make it process.exit(0) when everything is fine, process.exit(1) when it s wrong.
In your current program, instead of loading the file via require, use child_process.exec to invoke your new file, giving it the required parameter to know which file to test.
In your updated program, bind the close event to know if the return code was 0 or 1.
If you need more information than 0 or 1, into the new js file which will load the instruction, print some JSON.stringified data to stdout (console.log), and retrieve then JSON.parse it in the callback of call to child_process.exec.
Alternatively, have you looked into AST processing ?
http://jointjs.com/demos/javascript-ast
It could help you to identify piece of code which are not embedded within an exported function.
(Note: I discussed this question with the author on IRC. There may be some context in my answer that isn't in the original question.)
Given that your scenario is purely about preventing against accidental inclusion of non-instruction files, rather than about preventing malicious behaviour, static analysis using something like Esprima will probably be sufficient.
One approach would be to require that every instruction file exports some kind of object with a name property, containing the name of the instruction file. As there's not really anything to put in there besides a string literal, you can be fairly certain that if you can't locate a name property through static analysis, the file is not an instruction file - even in a language like JavaScript that isn't fully statically analyzable.
For any readers of this thread that are trying to protect from malicious actors, rather than accidents - for example, when accepting untrusted code from users: you cannot sandbox or 'validate' JavaScript with Node.js alone (not with the vm module either), and the above solution will not work for you. You will need system-level containerization or virtualization to run this kind of code safely. There are no other options.

How to detect if a mocha test is running in node.js?

I want to make sure that in case the code is running in test mode, that it does not (accidentally) access the wrong database. What is the best way to detect if the code is currently running in test mode?
As already mentioned in comment it is bad practice to build your code aware of tests. I even can't find mentioned topic on SO and even outside.
However, I can think of ways to detect the fact of being launched in test.
For me mocha doesn't add itself to global scope, but adds global.it.
So your check may be
var isInTest = typeof global.it === 'function';
I would suggest to be sure you don't false-detect to add check for global.sinon and global.chai which you most likely used in your node.js tests.
Inspecting process.argv is a good approach in my experience.
For instance if I console.log(process.argv) during a test I get the following:
[
'node',
'/usr/local/bin/gulp',
'test',
'--file',
'getSSAI.test.unit.js',
'--bail',
'--watch'
]
From which you can see that gulp is being used. Using yargs makes interpretting this a whole lot easier.
I strongly agree with Kirill and in general that code shouldn't be aware of the fact that it's being tested (in your case perhaps you could pass in your db binding / connection via a constructor?), for things like logging I can see why you might want to detect this.
Easiest option is to just use the detect-mocha [NPM package.
var detectMocha = require('detect-mocha');
if(detectMocha()) {
// doSomethingFancy
}
If you don't want to do that, the relevant code is just
function isMochaRunning(context) {
return ['afterEach','after','beforeEach','before','describe','it'].every(function(functionName){
return context[functionName] instanceof Function;
})
Where context is the current window or global.
I agreed with #Joshua on his answer, he says Inspecting process.argv is a good approach in my experience.
So, I've written a simple detecting mocha code.
const _MOCHA_PATH = new RegExp('(\\\\|/)node_modules\\1mocha\\1bin\\1_mocha$');
var isMochaRunning = process.argv.findIndex(arg => _MOCHA_PATH.test(arg)) > -1;
In a small project with no logging infrastructure, I use
if (process.env.npm_lifecycle_event !== 'test')
console.error(e);
to avoid logging expected errors during testing, as they would interfere with test output.

hunchentoot-based app in a lisp image (from buildapp) immediately returns

So I have an application using restas, based on hunchentoot.
At some point, I have the following function:
(defun main (args)
(declare (ignore args))
(set-config)
(restas:start '#:spa :port 8080))
(set-config) sets a few values related to database.
Anyway, I then use buildapp in the following way:
buildapp --output dist/spa --load-system spa --asdf-tree ~/quicklisp/ --entry spa::main --compress-core
Which works perfectly. The (set-config) function requires a config.json file to be present, and it indeed doesn't work when the file doesn't exist, so I know for sure that the application is correctly compiled.
When I run the generated binary however, the application immediately returns. Which means the HTTP server doesn't stay up.
I guess it's related to the fact that hunchentoot spawns a new thread, but it shouldn't stop the process, should it?
Also, I don't want to not use threads, i.e. I want the fact that each request is a separate thread.
So... I'm not sure exactly why it immediately returns. Why? And how to fix it?
I guess that you have to enter a main loop to keep the program running. The example at http://www.xach.com/lisp/buildapp/ uses the SBCL-specific (sb-impl::toplevel-repl nil).

Resources