electron-userland / spectron

DEPRECATED: 🔎 Test Electron apps using ChromeDriver
http://electronjs.org/spectron
MIT License
1.68k stars 229 forks source link

Spectron: Unable to interact with elements on electron application after launching the application #395

Open abhishek496 opened 5 years ago

abhishek496 commented 5 years ago

I am able to launch the electron app with Spectron but not able to perform any actions on it.

Here is my Spec.js file

var Application = require('spectron').Application;
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
const SearchPage = require('./page-objects/search.page');
const assert= require('assert');

describe('Test Suite', function () {
    this.timeout(20000);
    beforeEach('Start Application',  function () {
        this.app = new Application({
            path: 'path of .exe file located', // Ex: D:\\Foldername\\filename.exe
            requireName:'electronRequire',
            env: {
                NODE_ENV: 'test'
            }
        });
        chai.should();
        chai.use(chaiAsPromised);
        chaiAsPromised.transferPromiseness = this.app.transferPromiseness;
        return  this.app.start()
    });

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

    it('Sign In, function () {
         return this.app.client.
            .pause(20000) //waiting for login window
            .setValue(SearchPage.username, 'username').pause(1000)
            .setValue(SearchPage.password, 'password').pause(1000)
            .click(SearchPage.loginButton);
    });         

});

Package.json file:

{
  "name": "spectron-test-framework",
  "version": "1.0.0",
  "description": "Test Framework for Electron Desktop Application",  
  "main": "index.js",
  "scripts": {
    "test": "mocha --timeout 20000",
  },
  "author": "Tester",
  "license": "ISC",
  "devDependencies": {
    "webdriverio": "^4.10.2",
    "chai": "^4.1.2",
    "chai-as-promised": "^7.1.1",
    "electron": "^2.0.2",
    "mocha": "^5.2.0",
    "mochawesome": "^3.0.2",
    "spectron": "^3.8.0"

  }
}

OS: Windows 8.1 Node Version : 10.16.0

I am unable to interact the elements and seeing error as

1) Test Suite
       Sign In:
     Error: Timeout of 20000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (D:\spectron-example\Spec.js)

Even if I am increasing the timeout still seeing this timeout error.

How to fix this issue?

And my Questions are 1) Can we Start writing automation script without development code base ? because in most of the sample tests I have seen automation script is available in test folder of development code. 2) I have .exe while launching which I am able to see application being launched but not able to perform actions. Does .exe file needs to be provided to QA for automation with any specific packages and options enabled/disabled. 3) What are the Ideal Electron, Spectron, Nodejs, Wdio, Mocha compatible versions to work together?

Thanks In Advance.

jpolley commented 5 years ago

It looks like you are setting the timeout to 20 sec this.timeout(20000);, and in your it step the first thing you do is pause for 20 sec app.client.pause(20000) so that the timeout is reached before you try to setValue. Which would explain the output Error: Timeout of 20000ms exceeded.

But I experienced a similar error when I was getting started with spectron. I saw application launched properly and I could view login page but when I tried to interact with input fields I got: Error: unable to locate element. I tried using app.client.pause() to eliminate the chance of a timing issue but that didn't help.

Spectron does windowByIndex(0) and you as the test author need to manage the number of windows in your electron application. In our application there are a number of developer plugins (e.g. Devotion, React, MobX) that create their own window.

To diagnose the problem I used a wait strategy that would pause until app.client.getWindowCount() was equal to 4. But that wasn't a great solution because when new dev plugins were added later it would start to fail.

There was another tricky part. I couldn't just launch the app and simply tell it to focus on the fifth window. Because when the app first was initialized only 3 windows existed. It took a while for the last 2 windows to be initialized, and it took even more time for the page to be rendered. This required us to implement a better wait strategy so that we did not attempt to interact with the app before it was ready.

This solution may or may not work for you, but it has been solid for us. After initializing the client I use a function called waitUntilWindow and pass it the urlPart that is associated with our login page then do app.client.windowByIndex to set focus on the proper window. At that point I am able to interact with input fields and .setValue works like normal.

await waitUntilWindow(app, 'bundle=login', 'Login window never appeared.', 15000);

export async function waitUntilWindow(app, urlPart, msg, timeoutMs = 15000, interval = 150) {
  await app.client.waitUntil(
    async () => {
      return selectWindow(app, urlPart);
    },
    timeoutMs,
    msg || `Didn't see window with url part ${urlPart} in ${timeoutMs} ms.`,
    interval
  );
}

// Will return true if found the window with certain urlPart text in URL,
// or false if it did not.
export async function selectWindow(app, urlPart) {
  const windowCount = await app.client.getWindowCount();
  for (let i = 0; i < windowCount; i++) {
    await app.client.windowByIndex(i);
    const url = await app.client.getUrl();
    if (url.includes(urlPart)) {
      return true;
    }
  }
  return false;
}