-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
get the default process.stdout.write
back after tests are finished
#1582
Comments
@stevemao, I had a similar issue with tests that require the changing the behavior of My solution was to create a "helper" function that saves the original module.exports = function helper(fn) {
var originalConsoleLog = console.log;
function restore() {
console.log = originalConsoleLog;
}
if (fn.length) {
fn(restore);
else {
fn();
restore();
}
} Then ... in my tests I would ... var helper = require('/path/to/helper');
...
describe('...', function() {
// sync example
it('should ...', function() {
helper(function() {
var logs[];
console.log = function() { logs.push(arguments) }; // <-- or whatever you want to do
assert(...);
...
});
});
// async example
it('should ...', function(done) {
helper(function(restore) {
var logs[];
console.log = function() { logs.push(arguments) }; // <-- or whatever you want to do
assert(...);
asyncStuff(function() {
assert(...);
restore();
done();
});
});
});
}); This is just a rudimentary example, but I think you get the picture. You can easily adapt this to fit your particular use case. |
I do roughly the same thing as @JohnnyEstilles for any CLI-related tools: https://github.com/danielstjules/jsinspect/blob/master/spec/helpers.js https://github.com/danielstjules/jsinspect/blob/master/spec/reporters/jsonSpec.js Since I use node a lot for dev tools, I definitely have some bias towards saving a reference to |
The only reason I'd maybe lean towards having this behavior supported by Mocha is that you have to do cleanup from within a test, and can't rely on any hooks. So if your test errors out, you're not going to be able to restore |
@danielstjules, I do see your point. And, yes it would be very convenient (I do a lot of |
That would be super helpful! I should probably ping someone else here, cause like I said, I'm a bit biased :) |
Each test should be sandboxed in mocha and users should be able to do whatever dodge things inside each test. Users can change |
Alright, I'm convinced this is a good idea. :) @JohnnyEstilles If you'd like to submit a PR, feel free! Otherwise I might work on this tomorrow. |
@danielstjules ... Already started working on one. Will submit it soon. :-) |
@danielstjules, I went ahead and submitted my PR. It includes a module that I wrote a while back and am actively using in other projects, which happens to be a perfect fit for the issue @stevemao brought up. I included tests, but no docs (couldn't really find a place in the docs or the wiki where this could/should be documented). If you require docs for every PR just point me in the right direction and I'll write something up. :-) |
@stevemao / @danielstjules, sorry ... I closed my PR. @a8m and @travisjeffery seem to think this is not a good idea. @stevemao, it seems like your only recourse is to cleanup after yourself within each affected test, the same way I described in my initial comment. |
This is in reference to #1601 (comment) & #1601 (comment) Figured it'd be better posted in this issue since the PR was closed. @a8m @travisjeffery While I agree that proper dependency injection would go a long way, I feel like Mocha should at least maintain its own state. A spec shouldn't be able to break reporter output so easily. For example: var assert = require('assert');
describe('example', function() {
var output, write;
write = process.stdout.write;
beforeEach(function() {
output = '';
process.stdout.write = function(str) {
output += str;
};
});
afterEach(function() {
process.stdout.write = write;
});
it('I feel like this is acceptable', function() {
console.log('testing');
assert.equal(output, 'testing\n');
});
});
Note that there's no output because we modified |
@JohnnyEstilles Sorry about that. I'm hoping that something smaller in scope might work a bit better. |
@danielstjules ... no worries. I understand not everyone will agree with my madness. :-) |
@a8m Trying to keep the discussion in this one issue, I think @stevemao makes a valid argument: #1601 (comment) I think it's fine for us to recommend that user libraries make proper use of DI, but that same logic should apply to us, especially when it means a better user experience. I'd rather not make people jump through hoops to test a CLI tool. |
absolutely agree. and it's solved this issue as well. @danielstjules But this PR #1601 still feel me like a "patch" and cover up of things we don't need to. |
@a8m ... understood. That's why I withdrew my PR. |
I'm a little confused - what do you mean? |
Hmm I think we did not understand each other. |
I talked about this
|
Oh, gotcha! So we're in agreement that mocha should cache process.stdout.write for its own purposes? :) I think that's the easiest solution to this, without having to manage additional globals. Keeps things small in scope, as well. |
The way I see it, Mocha already does something similar to #1601, just on a smaller scale. It already saves a handful of functions from the global object to "avoid Sinon interfering". I supposed you could do the same with Short of my "patch and cover" solution, the only REAL solution to this would be to "actually" sandbox the testing environment. |
Yep, I agree with this, sorry for not seeing the issue before, too much work. |
"Saving" various functions that may or may not be modified by the test environment seems like an unscalable dead-end to me; please don't add more crap to the list. What are the implications of sandboxing the test environment? What kind of effort is required? Is this even feasible? Does it work in the browser? |
Is it feasible to grab the entire |
I don't think saving and restoring the entire I could restore stdout but tests might fail or user might forget to do so, etc as others have pointed out here. |
I'm not sure what |
So we save |
I've made my point quite clear here and most collaborators seem to be positive with this. |
This is pretty much what I was trying to do in #1601. (I know the consensus is that it's overkill.)
I constantly have the same issue with |
Let's make sure we're all on the same page here: It's not the test framework's responsibility to clean up after your tests. Does anyone disagree with this statement? If your test messes with globals, a reasonable expectation is that you will clean up after yourself. This is not impossible in the case of var expect = require('chai').expect;
describe('my nice test', function() {
var write, log, output = '';
// restore process.stdout.write() and console.log() to their previous glory
var cleanup = function() {
process.stdout.write = write;
console.log = log;
};
beforeEach(function() {
// store these functions to restore later because we are messing with them
write = process.stdout.write;
log = console.log;
// our stub will concatenate any output to a string
process.stdout.write = console.log = function(s) {
output += s;
};
});
// restore after each test
afterEach(cleanup);
it('should suppress all output if a non-AssertionError was thrown', function() {
process.stdout.write('foo');
console.log('bar');
// uncomment below line to suppress output, which is bad
// expect(output).to.equal(foobar);
expect(output).to.equal('foobar');
});
it('should not suppress any output', function() {
try {
process.stdout.write('foo');
console.log('bar');
// uncomment below line to just throw an AssertionError
// expect(output).to.equal('barfoo');
expect(output).to.equal(foobar); // ReferenceError
} catch (e) {
cleanup();
throw e;
}
});
}); So, I'm opposed to any sort of automatic restoration of
However, I'm not opposed to at least investigating a sandbox-type solution, as that might be a good idea anyway, if the level of effort is reasonable. If other collaborators disagree with me, please pipe up--otherwise I'd like to close this issue. |
yeah closing, adding this will lead to more pain (like getting support from people asking what magic is doing something) and needing more configuration (from people who want it turned off), etc. |
@boneskull I get your point here and I was/am actually doing this in my tests. But I'm not 100% happy with the syntax, especially the |
@stevemao Why the try-catch? You can use |
@dasilvacontin nope, since Mocha's reporter will try to print before the |
True. Wow, that sucks. Is there a way to listen to the If as a user you could listen to that event, you could avoid cleanup code from polluting the |
@danielstjules hmm that case does suck |
but that is definitely an edge case too |
Guys, if you think this is too much overhead for mocha, we should at least make it possible to build a plugin module to restore @travisjeffery if you wanna test output from a program this is pretty common IMO. |
@stevemao there's a ticket for a plugin api. i have some code written but not much |
So there is a way to listen to the |
Guys, originally I thought this was a bug (probably low priority) and wanted to have it fixed in this main module. I'm now convinced by @boneskull this is not a bug. However I still think this is a problem that needs to be solved in the future by a writing a document, plugin, addon or whatever. I suggest to reopen this but mark it as a lowest priority (I don't think this is too much overhead to solve anyways). |
I added this to the wiki https://github.com/mochajs/mocha/wiki/Mess-with-globals |
I didn't read through the whole thread but what I do instead of overriding |
@boneskull your example fails to provide a solution for async tests. In this case, it is mocha's responsibility to add a callback to the timeout function to allow developers to cleanup after themselves. The following would be required:
Without this fix, any test which does not call Currently, the only thing that can be done is:
I don't see a simpler way to solve this problem than to create a timeout callback (which I'm surprised doesn't exist right now). This would have to run before mocha tries to output result for the current test. Mocha is bleeding into my test scope, if I can't reasonably cleanup my test. |
It's not Mocha's responsibility to add and maintain some random API on demand. Mocha does not provide this level of isolation. If you need that, I'd suggest consuming |
I have a test which tests stdout so I need to change the default behaviour of
process.stdout
.mocha's report, however, cannot be seen any more if I use this. It would be good if mocha remembers the default
process.stdout.write
at the beginning and change it back after tests are finished.The text was updated successfully, but these errors were encountered: