-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
[WIP] Fix Console Logging in jsdom Env #2457
Conversation
document: ?Object; | ||
fakeTimers: ?FakeTimers; | ||
global: ?Global; | ||
moduleMocker: ?ModuleMocker; | ||
|
||
constructor(config: Config): void { | ||
constructor(config: Config, createJestConsole: (x: number) => Object): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could avoid breaking change by making createJestConsole
optional (I'd rename it to customConsole
). You could extract createJestConsole
to a separate module and use it as a default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was more thinking of the higher level context being dependent on env.console
. This change would require TestEnvironments to have a .console.getBuffer()
if they want their output included with the results.
// lazy require | ||
this.document = require('jsdom').jsdom(/* markup */undefined, { | ||
const jsdom = require('jsdom'); | ||
const con = this.console = createJestConsole(8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're assigning to this.console
. Be sure to remove the references to this field in dispose()
method, as this constructor is called for every test file (same for jest-environment-node
) and may cause memory leak.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thanks. I've tightened up the types too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this PR, looks really nice! Left some comments on things I would adjust. We'll need to wait for @cpojer to review it though.
I would love to move this creator function out to its own module, allowing me to remove it from the signature of the environment constructor (why have it at all then?). But when I attempted to do this, the package lines/dependencies got in my way. The creator function is here created as part of For me to do this, I'd have to shuffle a lot of these other dependencies around. :) |
// lazy require | ||
this.document = require('jsdom').jsdom(/* markup */undefined, { | ||
const jsdom = require('jsdom'); | ||
const con = this.console = createCustomConsole(8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the variable should be "console". No abbreviations please!
BufferedConsole.write([], type, message, 4), | ||
), | ||
); | ||
const createCustomConsole = (stackFrameDepth: number): Object => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think createConsole
should be good enough of a name, it implies that it is "custom".
I think I'd prefer moving this out of jest-cli into the appropriate packages so that the creator function is a stateless module rather than something we pass around. Just updated to node 7.3 and it seems indeed that logging is broken in that version using jsdom. Ugh, that's annoying. Maybe it is a regression in node that needs to be fixed? |
Hi everyone, @cpojer if you have the time, can you create an Issue in the node core?, if no one finds what happen I will take care of the Issue tonight. |
@italoacasas thanks. I created an issue here: nodejs/node#10492 but I'm on vacation right now and don't have time to create a more succinct and detailed repro. :( |
it's ok, don't worry, I think I have enough information. Thanks |
it looks like the commit that broke things was nodejs/node@524f693 the PR was nodejs/node#10227 While people are digging into this I'm going to look into adding jest to citgm so we can catch breakages like this earlier edit: currently it does not look like there is any easy way for us to include jest in citgm due to a variety of things mostly inherited from the monorepo approach. Let me know if you want to go more in depth and we can discuss. |
It seems like the Node fix is moving in the direction of a more correct vm module though, so either jest or jsdom is doing something weird. Let me know if it ends up being jsdom... |
I tried to figure out why When I ran this minimal script, assignment went just fine: const jsdom = require('jsdom');
const ctx = jsdom.jsdom(undefined, {});
const global = ctx.defaultView;
console.log(global.console);
global.console = 'test';
console.log(global.console); // this prints test BUT as soon as a I added Also, Also I see that the node commit above is for the Edit: Oh I see, it looks like the jsdom function returns the document, not the window object and |
in v7.3.0 the re-assignment fails. This is definitely what is causing the issue. /cc @domenic edit: we can alternatively set each of the individual methods in the console object var jsdom = require('jsdom');
const ctx = jsdom.jsdom(undefined, {});
const global = ctx.defaultView;
console.log(global.console.log.toString());
global.console.log = 'test';
console.log(global.console.log); // this prints test but I am not sure that is the exact functionality we want, we are also not guaranteed that other bits in jsdom are not broken by this change as well |
So it sounds like the issue is that now, in strict mode code, assigning |
I put up an alternative fix that's a bit simpler based on @dairyisscary's comments. It simply uses a non-strict module to set the console. This is a bit hacky and I expect this to break again in the future but it seems to me like this is a node/vm or jsdom issue as console should definitely be assignable or at least writable through |
I realized this doesn't just expand to |
@dairyisscary thank you so much for this PR and figuring out all these issues. I went ahead merging my own PR, which also fixes this issue for timers in node 7.3 and is a bit more minimal. Publishing 18.1 now but I'm hoping that this can be fixed in node or jsdom properly soon. |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
Jest currently supports great buffered output for printing to console (
console.log
,console.warn
, etc) but this only works in the officialnode
env. This PR aims to add this functionality to jsdom env too (very useful when debugging tests).Current master monkey patches in the jest console with this line, but this does not work on the jsdom object for whatever reason:
const testConsole = env.global.console = new TestConsole(
This PR consists of two commits, the first being a (broken) test demonstrating the desired behavior with jsdom env. The second commit is a proposed solution which fixes the failing test.
I have changed it so the test environment is responsible for constructing the console rather than the higher context with the above assignment. I have provided a factory function to the test environment's constructor since it seemed unreasonable to me for the environment to know how to and to duplicate this configuration logic. I was looking for some design input on this since this would break existing API, which probably wouldn't be a big deal except that its currently a supported use case for user to configure their own test environment.
Test plan
I have broken a boatload of tests because of the API change but I didn't want to waste time fixing them all if there are disagreements on the design.