statusfailed
statusfailed

Reputation: 900

zombie.js-triggered AJAX requests don't complete

I'm trying to write unit tests with Zombie.js. My problem is that AJAX requests aren't finishing when initiated using browser.evaluate, even though they execute fine when included on the page with a script tag.

I have three files:

index.html and hello.txt are served using the command python -m SimpleHTTPServer 8009. (note that I'm using dev.local, which is a synonym for 127.0.0.1 in my hosts file)

Here is index.html. It makes an AJAX request to retrieve hello.txt. This works fine:

<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8' />
    <title></title>
</head>
<body>
  <script type='text/javascript' src='https://code.jquery.com/jquery-2.2.0.min.js'>
  </script>
  <script type='text/javascript'>
    $.support.cors = true;
    var doRequest = function(msg) {
      $.support.cors = true;
      return $.ajax({
        url: "http://dev.local:8009/hello.txt",
        success: function(v) { console.log("success ", msg, v); }
      });
    };
  </script>
  <script type="text/javascript">
    console.log("page loaded");                                                                                                                                                    
    doRequest('script');
  </script>
</body>
</html>

Here's main.js. It navigates to index.html and tries to evaluate the doRequest function, which should cause an AJAX request. However, the request never completes, and instead times out.

var Browser = require("zombie");
const browser = new Browser({debug: true});
const rootURL = "http://dev.local:8009/"

browser.visit(rootURL, function(err) {                                                                                                                                             
  browser.evaluate('console.log("browser.evaluate ✔");');
  browser.evaluate('doRequest("zombie");');
});

Here is the log from running DEBUG=zombie node ./main.js:

  zombie Opened window http://dev.local:8009/  +0ms
  zombie GET http://dev.local:8009/ => 200 +38ms
  zombie Loaded document http://dev.local:8009/ +36ms
  zombie GET https://code.jquery.com/jquery-2.2.0.min.js => 200 +55ms
page loaded
  zombie XHR readystatechange http://dev.local:8009/hello.txt +64ms
  zombie XHR loadstart http://dev.local:8009/hello.txt +1ms
  zombie GET http://dev.local:8009/hello.txt => 200 +9ms
  zombie XHR readystatechange http://dev.local:8009/hello.txt +1ms
  zombie XHR readystatechange http://dev.local:8009/hello.txt +0ms
  zombie XHR readystatechange http://dev.local:8009/hello.txt +1ms
  zombie XHR progress http://dev.local:8009/hello.txt +0ms
success  script hello, world

  zombie XHR load http://dev.local:8009/hello.txt +2ms
  zombie XHR loadend http://dev.local:8009/hello.txt +0ms
  zombie Fired setTimeout after 0ms delay +1ms
  zombie Event loop is empty +0ms
browser.evaluate ✔
  zombie XHR readystatechange http://dev.local:8009/hello.txt +4ms
  zombie XHR loadstart http://dev.local:8009/hello.txt +0ms
  zombie GET http://dev.local:8009/hello.txt => 200 +6ms

Oddly, zombie seems to have actually completed the request: the final line of the log shows that a HTTP 200 response was received, but the event was never given to the handler.

Why doesn't the zombie-initiated request complete correctly?

Upvotes: 1

Views: 897

Answers (2)

Richard
Richard

Reputation: 2625

The above answer is correct. Using wait, you can get data that is ajaxed. Just another example to adapt by creating a function that accepts the browser as a parameter:

async function getAjaxedData(url, browser) {
    return browser.visit(url).wait().then(() => {
        // Do stuff
        // e.g. browswer.queryAll(selector)
    });
}

Upvotes: 0

Roland Starke
Roland Starke

Reputation: 1718

I got the same issue with zombie.js and so i looked at the source and found the following lines:

// -- Event processing --

// Grabs next event from the queue, processes it and notifies all listeners.
// Keeps processing until the queue is empty or all listeners are gone. You
// only need to bootstrap this when you suspect it's not recursing.
//... more lines ...
// Is there anybody out there?
if (this.waiting === 0)
    return;

so no events get fired if noone is waiting you need to add browser.wait()

browser.visit(rootURL, function(err) {                                                                                                                                             
    browser.evaluate('console.log("browser.evaluate ✔");');
    browser.evaluate('doRequest("zombie");');
    browser.wait();
});

Upvotes: 1

Related Questions