Unhandled 'error' event when running testem ci in windows. #359

Closed
tircnf opened this Issue Apr 7, 2014 · 10 comments

Comments

Projects
None yet
6 participants

tircnf commented Apr 7, 2014

I've been running into a problem with trying to run testem ci under windows with phantomjs.

node --version
v0.10.26

phantomjs --version
1.9.7

testem --version
0.6.14

to recreate.

npm install -g testem
npm install -g phantomjs
mkdir testem
cd testem

--create a spec.js file.


function hello() {return "hello";}

describe('hello', function(){
  it('should say hello', function(){
      expect(hello()).toBe('hello');
   });
});

make sure we have launchers defined.

testem launchers

info Seeking for config file...
Have 3 launchers available; auto-launch info displayed on the right.

Launcher      Type          CI  Dev
------------  ------------  --  ---
IE            browser       x
Chrome        browser       x
PhantomJS     browser       x

run the tests in ci mode.

The test runs properly in IE and Chrome, but an error is thrown when trying to use PhantomJS.

testem ci

ok 1 IE 9.0 - hello should say hello.
ok 2 Chrome 33.0 - hello should say hello.

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: spawn ENOENT
    at errnoException (child_process.js:988:11)
    at Process.ChildProcess._handle.onexit (child_process.js:779:34)    ...


If I cause PhatomJS to be run in dev mode, testem will hang, and I have to kill it with the task manager.

This happens on windows vista as well as windows 7.
it also happens under cygwin as well as a plain command prompt.
I ran into this by trying to run the ci task from lineman.

My workaround in my dev environment is to set launch_in_ci to only run Chrome.

Contributor

piuccio commented Apr 8, 2014

Very interesting, I hope you find the solution because I had the exact same problem. I couldn't fix it but I found a way to work around the problem in my use case.

Forgive me for this message, it's probably useless for your case but that's what I experienced. In my case tests were running perfectly fine on Windows (my personal machine) but failing on Jenkins (Linux, CI) with the same exception you have. I tried everything until I realized that even changing the code that spwans phantom to spwan echo banana was failing with the same exception.

The code I'm talking about is in lib/launchers.js around line 78

self.process = child_process.spawn("echo", ["banana"])

Now that didn't seem related to testem, phantom or any other dependency, but more of an environment problem.
Eventually I realized that my build was spawning two processes at the same time, something like this

* launch a command script (async)
* start tests
...
* end of command
...
* end of tests

The way I fixed my problem was to synchronize those two actions into something like

* start tests
...
* end of tests
* launch a command script (async)
...
* end of command

Once again, both setup worked just fine on one machine, but only the latter works on both of them.

Now, why does the browser work but not phantom? I don't know, but browsers are launched with child_process.exec while phantom with child_process.spawn, maybe it matters, maybe not.

I hope you'll find a better answer 😉

Collaborator

airportyh commented Apr 8, 2014

@tircnf thanks for the simplified test case. @piuccio thanks for your answer.

Unfortunately I still wasn't able to reproduce it, even on Windows 7. @tircnf you seemed to imply phantomjs actually works fine in dev mode, is that the case? The next thing I'd do to debug this is to try running phantomjs manually and see what happens. The script used within Testem is https://github.com/airportyh/testem/blob/master/assets/phantom.js

tircnf commented Apr 8, 2014

I did a little more digging. I saw in the docs you could run testem with a -d flag to get a debug log. Here is the output.

info Test'em starting...
info Seeking for config file...
info Starting ci
info Starting server
info spawning: C:\Program Files\Internet Explorer\iexplore.exe - ["http://localhost:7357/783"]
info New client connected: Mozilla/5.0 ....
info spawning: C:\Program Files (x86)\Google\Chrome\Application\Chrome<snip>,"http://localhost:7357/9170"]
info New client connected: Chrome 33.0 9170
info

I wasted a lot of time trying to figure out where the error was coming from, and why that last log line was empty. (it appeard that the error was happening before phantomJS was even being called) and finally figured out that the api.js replaces the log stream with

Api.prototype.configureLogging = function(){
  if (this.config.get('debug')){
    log.stream = fs.createWriteStream('testem.log')
  }else{
    var fakeStream = new EventEmitter
    fakeStream.write = function(){}
    log.stream = fakeStream
  }
}

the testem.log stream is not flushing before the program exits, and hiding the output.
I commented out the bottom 1/2 of the block so that debug output will continue to go to stdout.

and saw this extra line of output.

info spawning: phantomjs - ["C:\\Users\\Mike\\AppData\\Roaming\\npm\\node_modules\\testem/assets/phantom.js","http://localhost:7357/8182"]

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: spawn ENOENT
    at errnoException (child_process.js:988:11)
    at Process.ChildProcess._handle.onexit (child_process.js:779:34)

I added a block to catch the emitted error in launcher.js


    function spawn(exe){
      args = self.template(args, id)
      log.info('spawning: ' + exe + ' - ' + JSON.stringify(args))
      self.process = child_process.spawn(exe, args, options)
      self.stdout = ''
      self.stderr = ''
      // new error block
      self.process.on('error', function(errObj){
        log.error("Error trying to spawn " + exe)
        log.error(errObj)
        throw(errObj)
      })
     // end of error block
      self.process.stdout.on('data', function(chunk){
        self.stdout += chunk
      })
      self.process.stderr.on('data', function(chunk){
        self.stderr += chunk
      })
      self.process.once('close', self.onClose.bind(self))
      self.emit('processStarted', self.process)
      if (cb) cb(self.process)
    }

to finally get the following output.

info spawning: phantomjs - ["C:\\Users\\Mike\\AppData\\Roaming\\npm\\node_modules\\testem/assets/phantom.js","http://localhost:7357/1421"]
ERR! Error trying to spawn phantomjs
ERR! Error: spawn ENOENT

that is a really long winded way of saying that I was unable to spawn the executable "phantomjs"

so

C:\>where phantomjs
C:\Users\Mike\AppData\Roaming\npm\phantomjs
C:\Users\Mike\AppData\Roaming\npm\phantomjs.cmd

windows thinks I have two executable things called phantomjs

The first one "phantomjs" is a shell script to launch if you are using unix.
the second "phantomjs.cmd" is a .bat script for launching phantom.

I'm curious how your windows machine is able to launch phantomjs.

I can modify browser_launcher.js and change the name of the windows phantomjs exe to
phantomjs.cmd

    {
      name: 'PhantomJS',
      exe: 'phantomjs.cmd',
      args: buildPhantomJsArgs,
      supported: findableByWhere
    }

and I get a little closer...

info spawning: phantomjs.cmd - ["C:\\Users\\Mike\\AppData\\Roaming\\npm\\node_modules\\testem/assets/phantom.js","http://localhost:7357/9273"]
info New client connected: PhantomJS 1.9 9273

but from here the system just hangs.
and I have to cntl-c out of it.

And I just discovered the little oddity.

looking at the log, I can see that IE attached to a localhost session (with a unique id at the end).
then chrome did it.
then phantom (and the hang).

If I open up a browser and connect to the URL that either chrome or IE used, the test suite will finish. It will not finish if I connect to the URL of the phantomjs test.

here is the log file from a full run (with a few comments added in).

info Running testem.js from c:/Users/Mike/AppData/Roaming/npm/node_modules/testem
info Test'em starting...
info Seeking for config file...
info Starting ci
info Starting server
info spawning: C:\Program Files\Internet Explorer\iexplore.exe - ["http://localhost:7357/1993"]
info New client connected: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko 1993
info spawning: C:\Program Files (x86)\Google\Chrome\Application\Chrome.exe - ["--user-data-dir=C:\\Windows\\Temp\\testem.chrome","--no-default-browser-check","--no-first-run","http://localhost:7357/1508"]
info New client connected: Chrome 33.0 5051
info New client connected: Chrome 33.0 1508
info spawning: phantomjs.cmd - ["C:\\Users\\Mike\\AppData\\Roaming\\npm\\node_modules\\testem/assets/phantom.js","http://localhost:7357/899"]
info New client connected: PhantomJS 1.9 899
  ... system hangs here.
   .. but if I connect to  http://localhost:7357/1993 (the ie test)
                  or http://localhost:7357/1508 (the chrome test)
                  the test will then finish.
info New client connected: Chrome 33.0 1508

1..0
# tests 0
# pass  0
# fail  0

# ok

running phantomjs directly from the command line

phantomjs node_modules\testem\assets\phantom.js
just hangs.

So there is a little more light on a few things but I don't have a good answer on how to fix it.
the path to phantomjs can be different on different systems. (the two I built over the past few days both created phantomjs (bash script) and phantomjs.cmd (windows .bat file). I'm still curious as to how yours is working.

But fixing my path just opened up more questions to dig into. :(

tircnf commented Apr 8, 2014

Sorry I didn't answer your question about dev mode.

No, PhantomJS does not work when run in dev mode.
If I have two launchers configured for Dev (chrome and phantomjs), it kind of works.
The Chrome tests run, but phantomjs never connects. (and it shouldn't, because node is unable to spawn phantomjs).

Even though the chrome tests run, the "q" command does not work. If I keep hitting q I eventually get a warning about a possible memory leak.

The code does recognize the "q" command. (I see this in testem.log)
info Got keyboard Quit command

I have to pull up task manager and kill node.

after pressing q one time, the Chrome window goes away but the text based tab does not.
after pressing q 10 times, I see this warning logged to the console.

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
    at ChildProcess.EventEmitter.addListener (events.js:160:15)
    at EventEmitter.Launcher.kill (C:\Users\Mike\AppData\Roaming\npm\node_modules\testem\lib\launcher.js:165:13)
    at C:\Users\Mike\AppData\Roaming\npm\node_modules\testem\lib\dev\index.js:331:18
    at C:\Users\Mike\AppData\Roaming\npm\node_modules\testem\node_modules\async\lib\async.js:111:13
    at Array.forEach (native)
    at _each (C:\Users\Mike\AppData\Roaming\npm\node_modules\testem\node_modules\async\lib\async.js:32:24)
    at Object.async.each (C:\Users\Mike\AppData\Roaming\npm\node_modules\testem\node_modules\async\lib\async.js:110:9)
    at EventEmitter.App.cleanUpLaunchers (C:\Users\Mike\AppData\Roaming\npm\node_modules\testem\lib\dev\index.js:329:11)

    at EventEmitter.App.quit (C:\Users\Mike\AppData\Roaming\npm\node_modules\testem\lib\dev\index.js:206:10)
    at EventEmitter.App.onInputChar (C:\Users\Mike\AppData\Roaming\npm\node_modules\testem\lib\dev\index.js:222:12)

after I change the phantom exe to phantomjs.cmd, i git a similar response.
the test text ui starts, I get two tabs (one for chorme, one for phantom).

but I am unable to quit the app. (same deal with 'q'. it gets logged to testem.out. after 10 presses I get the memory leak message).

and lastly...

if I run in dev mode without any launchers, and then manually connect to testem using
phantomjs ....testem\assets\phantom.js http://localhost:7357

it will appear to run correctly.
except -- when I hit "q", the testem script exits properly, but the phantomjs script keeps on running.

I assume the phamtomjs has some kind of timeout, becuase after a few minutes it will request http://localhost:7357/socket.io/1/?t=bignumber and get a connection refused.
I am able to hit cntl-c to make the phantomjs script quit

Contributor

piuccio commented Apr 9, 2014

For what is worth

C:>where phantomjs
C:\Program Files (x86)\phantomjs-1.9.2-windows\phantomjs.exe

I've installed phantom manually, not from npm

Collaborator

airportyh commented Apr 9, 2014

@tircnf good on you for all that digging!

There are 2 issues:

  1. not finding phantomjs
  2. phantomjs started, but still hanging

For problem #1, you already found a workaround. Doing a where phantomjs on my Windows VM I got the same result as @piuccio

For problem #2, based on your findings, I would try to debug the phantomjs install. I suspect your phantomjs install is problematic. So try writing a small phantomjs script independent of testem, and see if you can get it to open up a web page and console.log etc, doing some mildly interesting things. If it looks broken, probably reinstalling it would solve the problem.

artoe commented Nov 3, 2014

Hi,

I had both issues in win7 with npm installed phantom. First I also added the .cmd ending in browser_launcher.js, but then discovered that sending SIGTERM (or even SIGKILL) to a .cmd process does not stop the phantom it has launched. So the phantom hangs. This was fixed by adding the phantomjs.exe directly into the path from %AppData%\npm\node_modules\phantomjs\lib\phantom.

The second issue for me was fixed by replacing clean_exit.js draining code to use a ready made node-exit (https://github.com/cowboy/node-exit) lib. I have created a pull request on this issue.

Collaborator

airportyh commented Nov 6, 2014

@artoe thanks for reporting. I just pulled a PR for making use of node-exit airportyh#421

Just ran into this too.

Looks like the testem/lib/launcher.js error,

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: spawn ENOENT
    at errnoException (child_process.js:988:11)
    at Process.ChildProcess._handle.onexit (child_process.js:779:34)    ...

is related to spawn not running phantomjs.bat when installed with npm. What's worse is, spawn isn't even able to run .bat files. (See joyent/node#2318)

I can confirm that downloading PhantomJS will work around this issue until either testem uses something like node-cross-spawn, or Node adds something like spawnShell as @isaacs suggested.

Owner

johanneswuerbach commented Dec 28, 2015

This is fixed in testem master now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment