Skip to content
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

Application.InitalizeClient fails to complete #219

Open
Flaque opened this issue Jul 29, 2017 · 10 comments
Open

Application.InitalizeClient fails to complete #219

Flaque opened this issue Jul 29, 2017 · 10 comments

Comments

@Flaque
Copy link

Flaque commented Jul 29, 2017

What I'm trying to do

I'm trying to run a basic test with Jest. I have two basic helpers that make the electron path and make the application:

function getElectronPath() {
  let electronPath = path.join(
    __dirname,
    "..",
    "node_modules",
    ".bin",
    "electron"
  );
  if (process.platform === "win32") {
    electronPath += ".cmd";
  }
  return electronPath;
}

function getApplication(buildPath) {
  const options = {};
  options.path = getElectronPath();
  options.args = [buildPath];
  if (process.env.CI) {
    options.startTimeout = 30000;
  }
  return new Application(options);
}

Then, I have a really simple test that opens up the electron app then counts how many windows there are:

import { getApplication } from "./helper.js";
import path from "path";

describe("Aurora", () => {
  let app;

  beforeEach(() => {
    const BUILD_PATH = path.resolve(__dirname, "..");
    app = getApplication(BUILD_PATH);

    return app.start();
  });

  afterEach(() => {
    if (app && app.isRunning()) {
      return app.stop();
    }
  });

  test("It shows initial window", () => {
    return app.client.waitUntilWindowLoaded().getWindowCount().then(count => {
      expect(count).toBe(1);
    });
  });
});

The Problem

When I try to run this, I'll get an error that says that the promise on app.start() in the beforeEach() call failed to complete:

Aurora › It shows initial window

    Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

      at pTimeout (node_modules/jest-jasmine2/build/queueRunner.js:53:21)
      at Timeout.callback [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:523:19)
      at ontimeout (timers.js:488:11)
      at tryOnTimeout (timers.js:323:5)
      at Timer.listOnTimeout (timers.js:283:5)

What I've tried so far.

1. Logging Application.prototype.start()

Inside my node_modules/spectron/lib/application.js file, I put a few console.log's in the Application.prototype.start call like so:

Application.prototype.start = function () {
  var self = this
  return self.exists()
    .then(function () { console.log("start chrome"); return self.startChromeDriver() })
    .then(function () { console.log("create client"); return self.createClient() })
    .then(function () { console.log("api init"); return self.api.initialize() })
    .then(function () { console.log("timeouts"); return self.client.timeouts('script', self.waitTimeout) })
    .then(function () { console.log("running"); self.running = true })
    .then(function () { console.log("return'd"); return self })
}

That printed out only:

start chrome
create client

So I know that it's never getting to the self.api.initialize() call. Which means the problem is in createClient

2. Checking createClient

Since createClient doesn't seem to have any promise calls until the end, I figured most of that must be executing. So to prove that, I put a console.log in the start of initializeClient to prove that we were at least getting there:

Application.prototype.initializeClient = function(resolve, reject) {
  console.log("initializeClient gets called");
  var maxTries = 10;
  var tries = 0;
  // ...
};

Sure enough, I'll get a message that says initializeClient gets called.

3. Checking initializeClient

Inside of initializeClient there's an init function that calls WebdriverIO's client.init function:

self.client.init().then(resolve, function(error)

To see where this was going, I checked to see if the function was being called and if it errorred:

  var init = function() {
    console.log("Starting an init function!");
    tries++;
    self.client.init().then(resolve, function(error) {
      console.log("There is an error in init!!");
      if (tries >= maxTries) {
        error.message =
          "Client initialization failed after " + tries + " attempts: ";
        error.message += error.type + " " + error.message;
        reject(error);
      } else {
        global.setTimeout(init, 250);
      }
    });
  };

I got a Starting an init function but no There is an error in init!! so I can assume that client.init got stuck somewhere.

4. Getting lost in WebdriverIO

So I went to go read webdriver's client.init code and I got a little lost here. It seems like /session call must have gotten lost somewhere.

return this.requestHandler.create({
        path: '/session',
        method: 'POST'
    }, {
        desiredCapabilities: this.desiredCapabilities
    })

But if it had some error, wouldn't it log it or throw it somehow? Isn't this supposed to be running locally too? So there shouldn't be latency. I'm not completely sure what's up.

Main Questions

Has anyone ever experienced anything like this? Does it have something to do with running on Jest? Have I made some simple mistake early on?

  • Thanks in advance <3
@Necmttn
Copy link

Necmttn commented Aug 7, 2017

let me tell you which part you did mistake,

the Spectron's new Application option takes the path to your application.

so it's should be

// Returns a promise that resolves to a Spectron Application once the app has loaded.
// Takes a Ava test. Makes some basic assertions to verify that the app loaded correctly.
function createApp (t) {
  return new Application({
    path: 'path/to/your/bundled/app',
    // args: ['-r', path.join(__dirname, 'mocks.js'), path.join(__dirname, '..')],
    env: {NODE_ENV: 'test'},
    waitTimeout: 10e3
  })
}

and i have another helper function which is

// Starts the app, waits for it to load, returns a promise
function waitForLoad (app, t, opts) {
  if (!opts) opts = {}
  return app.start().then(function () {
    return app.client.waitUntilWindowLoaded()
  }).then(function () {
    // change position
    app.browserWindow.setPosition(0, 0)
  }).then(function () {
    // Offline mode
    if (!opts.online) app.webContents.executeJavaScript('testOfflineMode()')
  }).then(function () {
    // Switch to the main window. Index 0 is apparently the hidden mesh-desktop torrent window...
    return app.client.windowByIndex(1)
  }).then(function () {
    return app.client.waitUntilWindowLoaded()
  }).then(function () {
    return app.webContents.getTitle()
  }).then(function (title) {
    // Note the window title is the HTML <title>
    t.is(title, 'browser-title', 'html title')
    return app
  })
}

and my helper test cases are looklike this,

let app

test.before(async t => {
  app = util.createApp()
  app = await util.waitForLoad(app, t)
})

test.beforeEach(async t => {
  t.context.app = app
})

test.afterEach(async t => {
  console.log('test complete')
})
// CleanUp
test.after.always(async t => {
  // This runs after each test and other test hooks, even if they failed
  await app.client.localStorage('DELETE', 'user')
  console.log('delete all files')
  const clean = await exec('rm -rf /tmp/DesktopTest')
  await clean.stdout.on('data', data => {
    console.log(util.format('clean', data))
  })
  // await app.client.close()
  await app.stop()
})

btw i'm using Ava test framework which is really developer friendly due of async & await support.

this setup should work if you face feature problem let me know.

@kontrollanten
Copy link

@Flaque I'm experiencing the same when running Spectron in Travis. I have problems debugging it though, because it only appears in Travis. Did you find any solution for this?

node version: 7.7.4

@kontrollanten
Copy link

kontrollanten commented Sep 2, 2017

Now I've managed to reproduce this error on my Mac. It seems like electron-chromedriver won't start when I pass in the chromeDriverLogPath option. When I try to run electron-chromedriver with cli I get

$ node node_modules/electron-chromedriver/chromedriver.js --port=9515 --url-base=/wd/hub --verbose --log-path=$(PWD)

Starting ChromeDriver 2.27 (44a803957cb27610c38f7e859016ac257959aeb5) on port 9515
Only local connections are allowed.
Failed to redirect stderr to log file.
Unable to initialize logging. Exiting..

It appears that should've read the docs and specified a path to a file for the chromeDriverLogPath.

It would be great if spectron could throw an error if the chrome driver fails to start. chromedriver exists with code 0, which makes it hard to determine.

Anyway, my error still appears in Travis. Even though it was fixed locally. When I check the webdriver log from Travis I see the following:

[20:29:24]  COMMAND	POST 	 "/wd/hub/session"
[20:29:24]  DATA		{"desiredCapabilities":{"javascriptEnabled":true,"locationContextEnabled":true,"handlesAlerts":true,"rotatable":true,"browserName":"electron","chromeOptions":{"binary":"/Users/travis/build/app/application/node_modules/spectron/lib/launcher.js","args":["spectron-path=/Users/travis/build/app/application/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron","spectron-arg0=.","spectron-env-DEBUG=false","spectron-env-NAME=test"]},"loggingPrefs":{"browser":"ALL","driver":"ALL"},"requestOrigins":{"url":"http://webdriver.io","version":"4.6.2","name":"webdriverio"}}}

It looks like the chromedriver won't start even there.

Edit:

Solution: I forked spectron and printed all the stdout from chromedriver to console. There I found out that my application threw an error upon start, once that was solved everything works as expected. Ie there was no problem with starting chromedriver.

@TalKashi
Copy link

TalKashi commented Oct 3, 2017

Hi,
I am experiencing the same issue, getting stuck on the client.init call.
I can see my app is starting (by it's log file).
I have tried both giving in the new Application options the path to my app executabel and path to electron.exe and in args array path to my app folder. Both are failing.

Running on windows 7, electron 1.7.6 spectron 3.7.2

Any help would be appreciated!

@shiruba
Copy link

shiruba commented Dec 7, 2017

Same here, stuck in the client.init call. The app is starting multiple times, even after the callback times out.

Additionally, logging seems to be enabled only when I configure webDriverLogPath.
chromeDriverLogPath has no effect at all.

@ericyahhh
Copy link

Seeing the same problem on Circle CI only (Works locally and on Travis CI).

@kontrollanten Any hint on how to do this: printed all the stdout from chromedriver to console?

@kontrollanten
Copy link

@ericyahhh
Copy link

@kontrollanten Thank you very much – I'll try that out now.

@dustmop
Copy link

dustmop commented Jan 13, 2020

Ran into this problem last week and spent the last few days trying to figure it out. Symptoms were the same: the app would halt at WebdriverIO.init, except I was only seeing this failure on Windows and not on Mac. The only thing that fixed it for me was changing the path option for the Application constructor to use the project's "node_modules/electron/dist/electron.exe", and passing my project's source directory using args.

let electronAppPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', 'electron');
  if (process.platform == 'win32') {
    electronAppPath = path.join(__dirname, '..', '..', 'node_modules', 'electron',
                                'dist', 'electron.exe');
  }
  app = new Application({
    path: electronPath,
    args: [path.join(__dirname, '..', '..', 'app')],

Things I tried that had no effect:

  • using the electron.cmd batch script
  • modifying chromeDriverArgs or chromeDriverLogPath at all
  • using a different chromedriver version
  • making my spectron minor version exactly match electron. ended up on electron 7.1.7 and spectron 9.0.0
  • modifying webPreferences.nodeIntegration
  • probably other things that I forgot about

Hope that someone finds this useful.

@UberMouse
Copy link

I stumbled across this issue in my search for a solution to a similar problem. I'm unclear if other people on this issue were having their Electron app start up or not, but I was so none of the suggestions seemed applicable as Spectron clearly had the right Electron path and the app was not throwing an error during boot.

I eventually tracked the problem down to this issue in the Electron repository. All I needed to fix it was to pass the --remote-debugging-port=12209 argument as part of the chromeDriverArgs and it started working fine.

Hope this saves someone else the day I lost hunting this down 😬

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants