1

I'm having a problem where Zombie.js is throwing an error Error: Timeout: did not get to load all resources on this page.

It's always super random and always seems to happen on a different test.

I used to have the following line of code to prevent this issue.

Browser.waitDuration = '60s';

Problem is recently Stripe.js was causing this problem where my unit tests took an extra 55 seconds. See this question.

So Stripe advised me to remove that line. And sure enough my tests started running faster again.

But I had forgotten that I added that line to prevent this timeout error.

Any ideas on how to fix this while making sure my unit tests don't take an unreasonably long time?

Charlie Fish
  • 18,491
  • 19
  • 86
  • 179
  • Perhaps a lower waitDuration, catching the error and proceeding anyway is an option? – ippi May 28 '17 at 00:43
  • @ippi How exactly would that work? I don't want to proceed and mark the test as successful if it failed. I just want my tests to not take a full minute each and not timeout randomly and for seemingly no reason haha. – Charlie Fish May 28 '17 at 00:45
  • Yeah, failing the tests of course, but if it happens in different places every time maybe that's acceptable. That is: catching the errors with `zombie.on("error", callback)` check that the errors actually are timeouts (and throw again when they are not) and maybe log a line or two. – ippi May 28 '17 at 01:01
  • I'm sure you have seen https://github.com/assaf/zombie/issues/882 by now. Google analytics seems to be one villain, memory leak another. (Sorry, just throwing in some ideas.) – ippi May 28 '17 at 01:05
  • @ippi Ok that kinda makes sense. I do see memory usage go up to over 1.4gb or so. I don't see any similarities between when it fails and memory exactly tho. In terms of that zombie.on error what do you mean by throw again when they are not and maybe log a line or two? I mean I know the issue is timeouts. At least that's what it says when the test fails. I'm just not sure how to like bypass that or solve the issue. I do think Stripe recently integrated something similar to Google Analytics to view time on page (just a guess but seems likely), which is why this broke. – Charlie Fish May 28 '17 at 01:08
  • I just meant that you have to throw the error yourself when it's not a timeout. (Since node won't throw anything anymore if you catch all errors. ) – ippi May 28 '17 at 01:14
  • @ippi Ok well I don't think that is an issue. So I will implement that zombie.on error. If it's not a timeout throw the error. If it is a timeout how should I handle that? – Charlie Fish May 28 '17 at 01:22
  • @ippi And how exactly would I check to see if the error in zombie.on is a timeout error? – Charlie Fish May 28 '17 at 01:29
  • `.on('error', (err) => { }` This catches all errors, it's not zombie specific but node's EventEmitter. By doing this no errors will throw an exception. So you can compare `if (err.name !== "Timeout") throw err;`. Here however, I'm guessing on the error name, since I don't know the real one. (log it with console.log(err.name)). There are other ways of comparing errors as well - using `instanceof` is pretty common. – ippi May 28 '17 at 01:34
  • @ippi Ok and what do I want to do if the error is a timeout error? – Charlie Fish May 28 '17 at 01:35
  • Nothing, you just let it continue. :) Or maybe add a log entry. – ippi May 28 '17 at 01:36
  • @ippi How would that solve the problem? Because the whole problem right now is without `Browser.waitDuration = '60s';` the test times out because of Zombie.js. – Charlie Fish May 28 '17 at 01:37
  • Yeah, it doesn't fix the problem. I'm just saying maybe it's ok to ignore it. Sweep it under the rug. – ippi May 28 '17 at 01:40
  • @ippi Ok the problem is the `done()` function never gets called. So mocha timesout after a certain amount of time as well (I think I have my mocha timeout set pretty high). If Zombie.js throws that error then it doesn't finish the test therefor `done()` is never called and mocha says the test is a failure since it didn't finish. – Charlie Fish May 28 '17 at 01:42

1 Answers1

1

I have never used Zombie.JS, but I've used PhantomJS quite a bit, and I ran into similar issues. My solution was to block unnecessary resources which reduced my request / response times to milliseconds -- for the most part -- during testing.

There is a discussion in another zombie.js-related question where the OP wants to block external resources like Google Analytics:

Prevent zombie.js from loading only external resources

There are two answers provided. One -- the Chosen Answer -- pertains to pre-3.1 zombie.js and the second (non-chosen answer) explains how you might use the 'nock' npm module to stub external resources.

Sorry, but I don't have time to work out any examples. However, I do have a gist with an example of blocking resources in PhantomJS: https://gist.github.com/mootzville/15af584e626b365d2664

Maybe that can give you some ideas.

Good luck.

EDIT (Jun 3, 2017):

I played around with the code you provided in your comment. Below is a sample of some code that should work for you using zombie and nock together:

nock('https://js.stripe.com')
  .get('/v2')
  .replyWithFile(200, __dirname + '/stripev2.js');

var Browser = require('zombie');
var browser = new Browser();
var url = 'https://js.stripe.com/v2';


browser.fetch(url)
  .then(function(response) {
    console.log('Status code:', response.status);
    if (response.status === 200)
      return response.text();
  })
  .then(function(text) {
    console.log('Document:', text);
  })
  .catch(function(error) {
    console.log('Network error');
  });

Just to clarify, the stripev2.js file should exist locally in the same directory as the entry point -- if you were following Node conventions, then it would be where your app.js or index.js file is (typically, the root dir of the app).

Levi Mootz
  • 306
  • 1
  • 4
  • Just got around to trying this. I have the following code `nock('https://js.stripe.com/v2').log(console.log).get('/').replyWithFile(200, __dirname + 'stripev2.js');` and I get an error saying `ReferenceError: window is not defined`. Not sure why that is happening because it should just be sending the local file instead of making a web request. – Charlie Fish Jun 02 '17 at 05:45
  • @CharlieFish - I'd like to help you further, but just don't have time at the moment to dig into more code; I'm buried in my own and others already. I'd recommend you play around with PhantomJS. I know it's a new thing...but once you get the hang of it, you'll be able to do everything you ever wanted testing / automation-related with the browser. – Levi Mootz Jun 02 '17 at 21:18
  • @CharlieFish - See the code in my edit above. Hope this works for you. – Levi Mootz Jun 03 '17 at 10:59