I have a loop of tests running in intern-geezer, with about twenty out of a hundred very similar tests running successfully. Then suddenly:
FATAL ERROR
ReferenceError: window is not defined
and the loop stops. There are no explicit calls to window or document in my code. It's pure JS. I'm using intern-geezer, 2.2.2. The line numbers referenced in the error stack make absolutely no sense. They're way off.
I've read the suggestion to switch from the command:
./node_modules/.bin/intern-client config=tests/intern
to:
./node_modules/.bin/intern-runner config=tests/intern
but I don't want to connect to a server or open a browser (there's a separate, strange loading error occurring there which seems specific to geezer). I want to get this going at the command line. Grateful for any help, I'm totally new to Intern.
window is a browser object, so it's not going to be available in Node. If you want to run tests exclusively in the node client (intern-client), you'll need to make sure you're not using (and none of your dependencies are using) any code that references browser objects like document, window, navigator, etc.
If the stack trace line numbers are off, it's probably the code coverage instrumentation. You can disable that by setting the excludeInstrumentation property in your Intern config to /./.
You probably set 'Html' as reporter in your intern configuration file :
intern.reporters = [
{ id: 'Html' },
{ id: 'JUnit', filename: 'test-reports/quality/functional/junit.xml' },
...,
];
Related
The content of (new Error('foo')).stack looks something like this:
Error: foo
at Object.notifier (http://localhost:6969/js/main.js:12705:37)
at trackHookChanges (http://localhost:6969/js/main.js:1813:27)
at UseState (http://localhost:6969/js/main.js:1982:13)
at K._.data (http://localhost:6969/js/main.js:70174:6005)
at K (http://localhost:6969/js/main.js:70174:6380)
at Z (http://localhost:6969/js/main.js:70174:9187)
However, when I console.log it, it looks like:
Error: foo
at Object.notifier (wdyr.ts:10)
at trackHookChanges (whyDidYouRender.js:1306)
at UseState (whyDidYouRender.js:1475)
at K._.data (index.esm.js:1)
at K (index.esm.js:1)
at Z (index.esm.js:1)
Is Chrome devtools is using sourcemaps to automatically change the string being logged? Is it there an easy way to access the source file names in my code? I want to ignore errors originating from certain NPM module.
Unfortunately (but luckly for devs) yes, Chrome uses sourcemaps to format errors in the console and there is (still) no way to access the same function it uses or output it produces. Even if it was possible, it would work only on a specific browser/platform.
TLDR
Emulate the browser sourcemap resolution with StackTraceJS or filter your errors by their prototype or any of their properties (like Error.message for example)
Discussion
JS Errors stacktrace are a mess, and so unreliable:
they are very dependant on the running environment, if you run code on Chrome you could end up with a different stack with respect of running it on Firefox, IE or node (even if in the latest times they are reaching to a "stacktrace agreement" between environments).
The maximum length of the error stacktrace is (almost always) 10 lines, so if your function (hook) was called before that time you will never catch it.
internal or delayed callbacks can erase/change/augment the stacktrace of a function in certain environments (it can be very hard, sometimes impossible, to catch the full stacktrace of a callback called inside a setTimeout for example)
Partial solution (StackTraceJS)
If you can afford to make a http request for a sourcemap, you can exploit the same mechanism that Chrome (or any other browser) uses to parse and map the error stacktrace files into the original files and filter those you don't like. The downside of this operation is that your code must be completely reworked with promise-like chain (because of the http request).
Luckly there is already a library which makes this process much much easier: StackTraceJS, you can give it a try.
This would be its usage (from library docs):
var error = new Error('BOOM!');
StackTrace.fromError(error).then(callback).catch(errback)
/*
==> Promise([
{functionName: 'fn', fileName: 'file.js', lineNumber: 32, columnNumber: 1},
{functionName: 'fn2', fileName: 'file.js', lineNumber: 543, columnNumber: 32},
{functionName: 'fn3', fileName: 'file.js', lineNumber: 8, columnNumber: 1}
], Error)
*/
Side Note
As you stated in the question comment, you are using React, and the usual working pipeline is using wepack or other js bundler to output a single JS file from all the dependencies. During developing you could encounter no problems to find out the file from the errors stack, but in production you could omit sourcemap informations from the bundle or either have some internal/uglified filenames which are not linked with the original file. This means that the behaviour of your code could change between dev/prod configuration depending on your building pipeline.
Theoretical solution
The (proto-OOP) theory states to use prototype to discriminate between Error types in order to filter unwanted behaviours.
So first of all you should use a custom class to define the errors thrown by your application/library (see Custom Error - MDN section). By doing so you must throw or extend only your CustomError(s) in your code.
Secondly you should filter the error by its type/properties and not by its source file, so (if you can) check what classes of Error the 3rd party function can throw.
In this way it's easy to isolate only those 3rd party errors, you can do just a simple check of inheritance within the try/catch block:
try { /* dangerous code */ }
catch (ex) {
if (ex instanceof MyError) { /* handle your errors */ }
else if (ex instanceof The3rdPartyCustomError) { /* handle specific 3rd party CustomError */ }
else if (ex.__proto__ instanceof Error) { /* handle generic 3rd party CustomErrors */ }
else { /* handle native errors (or bad practice 3rd party errors) */ }
}
But all of this theory can be difficult to implement, especially because 3rd party libraries very rarely implement their CustomError classes, so you will end up to handle only native errors and your defined classes.
Give it a try and check what kind of errors can throw your 3rd parties libs.
Maybe the simpler solution is to filter the erros by Error.message or any other properties which could work better than expected in your domain case.
I have a question regarding the Uglify JS module, in the usecase of webpack plugin.
My codebase have several console.log statements around the code for debugging purposes localy, it will only be printede out in development mode, but they are still taking up space in the codebase and i dont what them in the production build but, i would like to keep my console.error and console.warn still.
I know the Uglify JS have key drop_console flag but that kills every console output there is and i still want the warnings and errors in my console.
The reason for this question is i have a custom error handler than ships errors to Sentry, and I want to read the error in the console when it happens, so i use the error and warning console out put.
From docs:
drop_console (default: false) -- Pass true to discard calls to console.* functions. If you wish to drop a specific function call such as console.info and/or retain side effects from function arguments after dropping the function call then use pure_funcs instead.
...
pure_funcs (default: null) -- [...] You can pass pure_funcs: [ 'Math.floor' ] to let it know that this function won't produce any side effect, in which case the whole statement would get discarded.
So the option you're looking for is pure_funcs: [ 'console.log' ]
Update 2:
After forgetting about this for a week (and being sick), I am still out of my depth here. The only news is that I reran the tests in Safari and Firefox, and now Safari always fails on these tests, and Firefox always times out. I assume I've changed something somewhere, but I have no idea where.
I'm also more and more certain there's a timing issue somewhere. Possibly simply code going async where it shouldn't, but more likely it's something being interrupted.
Update:
I'm less interested in finding the actual bug, and way more interested in why it's intermittent. If I can find out why that is, I can probably find the bug, or at least rewrite the code so it's avoided.
TL;DR:
I'm using Karma (with Webpack and Babel) to run tests in Chrome, and most of them are fine, but for some reason 7 tests get intermittent failures.
Details:
So! To work!
The six first tests MOSTLY succeed when I run it in the debug tab, and MIGHT fail. The failure percentage seems higher when running it normally, though. These six tests are related, as they all fail after running a specific method which functions as a safe delete() for some Backbone models. Basically it's meant to check and clear() all linked models in the model to be deleted, and return false if it's not able to do that.
And had the failures been 100%, I am sure I would find the error and wink it out, but the only thing I know is that it has to do with trying to access or change a model that has already been deleted, which seems like it's a timing thing...? Something being run asynchronously but shouldn't perhaps...? I have no idea how to fix it...
The seventh test is a little easier. It's using Jasmine-Jquery to check if a dom element (which starts out empty) gets another div inside after I change something. It's meant to test if Bootstrap's Alert-system is implemented correctly, but has been simplified heavily in order to try to find out why it fails. This test always fails if I run it as a gulp task, but always succeeds if I open the debug tab and rerun the test manually. So my hypothesis is that Chrome doesn't render the DOM correctly the first time, but fixes it if I rerun it in the debug tab...?
TMI:
When I say I open the debug tab and rerun the test manually, I am still inside the same 'gulp test' task, of course. I also use a 'gulp testonce', but the only change there is that it has singleRun enabled and the HTML reporter enabled. It shows the exact same pattern, though I can't check the debug page there, since the browser exits after the tests.
Output from one of the first 6 tests using the html reporter.
Chrome 47.0.2526 (Mac OS X 10.11.2) model library: sentences: no longer has any elements after deleting the sentence and both elements FAILED
Error: No such element
at Controller._delete (/Users/tom/dev/Designer/test/model.spec.js:1344:16 <- webpack:///src/lib/controller.js:107:12)
at Object.<anonymous> (/Users/tom/dev/Designer/test/model.spec.js:143:32 <- webpack:///test/model.spec.js:89:31)
Output from test 7 using the html reporter.
Website tests » Messaging system
Expected ({ 0: HTMLNode, length: 1, context: HTMLNode, selector: '#messagefield' }) not to be empty.
at Object.<anonymous> (/Users/tom/dev/Designer/test/website.spec.js:163:39 <- webpack:///test/website.spec.js:109:37)
Now, the first thing you should know is that I have of course tried other browsers, but Safari has the exact same pattern as Chrome, and Firefox gives me the same errors, but the error messages end up taking 80MB of diskspace in my html reporter and SO MUCH TIME to finish, if it even finishes. Most of the time it just disconnects - which ends up being faster.
So I ended up just using Chrome to try to find this specific bug, which has haunted my dreams now for a week.
Source
Tests:
https://dl.dropboxusercontent.com/u/117580/model.spec.js.html
https://dl.dropboxusercontent.com/u/117580/website.spec.js.html
Test output (Since the errors are intermittent, this is really just an example): https://dl.dropboxusercontent.com/u/117580/output.html
OK, all tests now succeed. I THINK this was the answer:
Some tests called controller, and some tests called window.controller. This included some reset() and remove() commands.
After doing a rewrite, I still had failures, so I did another rewrite. As part of that rewrite, I decided to make all calls through window.*, and after that rewrite all tests succeeded.
I have a long CasperJS script. When I run it I get:
phantomjs file.js
SyntaxError: Parse error
Is there a way to get some more information about the error.
At least a line number? or any hint at all?
Try run the file.js with node, so for your example:
node file.js
It's not possible to determine this in PhantomJS itself. The documentation on phantom.onError says:
This is the closest it gets to having a global error handler in PhantomJS
And this doesn't catch the syntax error. If you try to run it with the --debug=true option, you will see a lot of debug messages, but the final error has still the same amount of information.
Another thing that I tried was to use a second PhantomJS script which reads the original script and tries to eval it. The phantom.onError event is triggered in this case, but the trace argument is empty.
The good thing is that PhantomJS/CasperJS scripts are just JavaScript, so you can paste them to http://jslint.com/ or run a dedicated jslinter on them to see where the problem lies. There are some options that you have to mark on the site or otherwise you will get a lot of errors:
add phantom to the global variables box,
enable node.js mode and
tolerate "everything" (or those things that you actually want to tolerate)
I spent a whole 8hrs on this to find a trick for this problem. The trick is to run "phantomjs" and type 'require "path_to_js_file"'. I used 2.1.1 version of phantomjs. Likely 2.2 also works.
Then there will be a stack trace that shows which line is the offender. You won't see this in testem output.
In my case, if you define a property twice for an object, it will work for chrome, firefox etc, but not phantomjs. Lint might help but there are >5K lint errors for the project I work on and it is practically impossible to see what's wrong. Also the particular problem is likely hidden under the same bucket of "javascript strict mode violation". Nodejs didn't complain this either.
I'm trying to debug a DOM scraping packaged called crowbar. Anyhow, when I run I get:
Error: [Exception... "Component returned failure code: 0xc1f30001 (NS_ERROR_NOT_INITIALIZED) [nsIServerSocket.asyncListen]" nsresult: "0xc1f30001 (NS_ERROR_NOT_INITIALIZED)" location: "JS frame :: chrome://crowbar/content/crowbar.js :: onLoad :: line 375" data: no]
Source File: chrome://crowbar/content/crowbar.js
Line: 375
Basically, asyncListen() is throwing NS_ERROR_NOT_INITIALIZED. This is weird because the line of code immediately before this is a call to init()! I've tried adding:
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
just before the call to asyncListen() and it had no effect. Is this a security issue? (btw, in case it matters, this is on a Fedora box, running as root, with selinux disabled)... I've also tried a few different port numbers...
Here's the source code: http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsServerSocket.cpp#369
Are you sure init() doesn't fail (that's what initializes mFD)? Maybe something closes it before your call?
I would build a debug XULRunner to build a debug version and/or try to get logging output from the app. Unfortunately, I can't figure out what the LOG() macro in that code resolves to, usually it's NSPR logging, but you have to guess the module name in order to enable logging for this module.
Boris Zbarsky (one mozilla core developers) says:
Since you're calling init(), the only other way I see to get an
NS_ERROR_NOT_INITIALIZED out of asyncListen is for the thread you're running on
to no longer be accepting events...
So something odd is happening. Are there in fact multiple threads involved?
I am too facing this problem. I have derived my code from CrowBar and running it through xulrunner 1.9.1 on Win 7.
I get the problem when I am diconnected from the net. If I am on a network it works. I do have multiple threads [multiple xul elements ]. But I belive I am running it on main thread (I am not sure how I can find current thread though), so thread not listening should not be the issue.
Also I have noted that in nsSocketTransportService2.cpp thread becomes null, so Boris maybe right.
NS_IMETHODIMP
nsSocketTransportService::Dispatch (nsIRunnable *event, PRUint32 flags)
{
LOG(("STS dispatch [%p]\n", event));
nsCOMPtr<nsIThread> thread = GetThreadSafely();
NS_ENSURE_TRUE(thread, NS_ERROR_NOT_INITIALIZED);
nsresult rv = thread->Dispatch(event, flags);
if (rv == NS_ERROR_UNEXPECTED) {
// Thread is no longer accepting events. We must have just shut it
// down on the main thread. Pretend we never saw it.
rv = NS_ERROR_NOT_INITIALIZED;
}
return rv;
}
Hope this helps pin down the problem.
thanks
harvinder