Skip to content

Commit

Permalink
#13173 WinAppDriver does not wait long startup an UWP app
Browse files Browse the repository at this point in the history
add create session timeout and waitForCondition to retry the session creation in case of an err
add 'createSessionTimeout' capability for WindowsDriver only
  • Loading branch information
Korop committed Sep 16, 2019
1 parent 46c4e66 commit 07b8e4c
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 8 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ let driver = new WindowsDriver();
await driver.createSession(defaultCaps);
```

## WindowsDriver-specific capabilities

|Capability|Description|Values|
|----------|-----------|------|
|`createSessionTimeout`|Timeout in milliseconds used to retry `WinAppDriver` session startup. This capability could be used as a workaround for the long startup times of UWP applications (aka `Failed to locate opened application window with appId: TestCompany.my_app4!App, and processId: 8480`). Default value `20000`|e.g., `15000`|


## Watch code for changes, re-transpile and run unit tests:

```
Expand Down
3 changes: 3 additions & 0 deletions lib/desired-caps.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const desiredCapConstraints = {
// recognize the cap,
// but validate in the driver#validateDesiredCaps method
},
createSessionTimeout: {
isNumber: true
},
calendarFormat: {
isString: true
},
Expand Down
49 changes: 42 additions & 7 deletions lib/winappdriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ import { JWProxy } from 'appium-base-driver';
import log from './logger';
import { SubProcess } from 'teen_process';
import { WAD_INSTALL_PATH, verifyWAD } from './installer';
import { retryInterval } from 'asyncbox';
import { retryInterval, waitForCondition } from 'asyncbox';
import cp from 'child_process';
import B from 'bluebird';

const REQUIRED_PARAMS = []; // XXYD 1-5-2018: removed app from required params because you can alternatively use appTopLevelWindow
const DEFAULT_WAD_HOST = '127.0.0.1';
const DEFAULT_WAD_PORT = 4724; // should be non-4723 to avoid conflict on the same box
const DEFAULT_WAD_PORT = 4724; // should be non-4723 to avoid conflict on the same box;
const DEFAULT_CREATE_SESSION_TIMEOUT_MS = 20000; // retry start session creation during the timeout in milliseconds

class WinAppDriver extends events.EventEmitter {
constructor (opts = {}) {
const {host, port} = opts;
const {host, port, createSessionTimeout} = opts;
super();

for (let req of REQUIRED_PARAMS) {
Expand All @@ -25,6 +26,7 @@ class WinAppDriver extends events.EventEmitter {

this.proxyHost = host || DEFAULT_WAD_HOST;
this.proxyPort = port || DEFAULT_WAD_PORT;
this.createSessionTimeout = createSessionTimeout || DEFAULT_CREATE_SESSION_TIMEOUT_MS;
this.proc = null;
this.state = WinAppDriver.STATE_STOPPED;
this.jwproxy = new JWProxy({server: this.proxyHost, port: this.proxyPort});
Expand Down Expand Up @@ -74,15 +76,15 @@ class WinAppDriver extends events.EventEmitter {
this.changeState(WinAppDriver.STATE_STOPPED);
}
});
log.info(`Spawning winappdriver with: ${args.join(' ')}`);
log.info(`Spawning WinAppDriver with: ${args.join(' ')}`);

// start subproc and wait for startDetector
await this.proc.start(startDetector);
await this.waitForOnline();

} catch (e) {
this.emit(WinAppDriver.EVENT_ERROR, e);
// just because we had an error doesn't mean the winappdriver process
// just because we had an error doesn't mean the WinAppDriver process
// finished; we should clean up if necessary
if (processIsAlive) {
await this.proc.stop();
Expand Down Expand Up @@ -130,8 +132,41 @@ class WinAppDriver extends events.EventEmitter {
}

async startSession (caps) {

let createSessionTimeout = this.createSessionTimeout;
if (caps.createSessionTimeout) {
createSessionTimeout = Number.isInteger(caps.createSessionTimeout) ? caps.createSessionTimeout : parseInt(caps.createSessionTimeout, 10);
}

log.info(`Start WinAppDriver session during createSessionTimeout = '${createSessionTimeout}' ms.`);
this.proxyReqRes = this.jwproxy.proxyReqRes.bind(this.jwproxy);
await this.jwproxy.command('/session', 'POST', {desiredCapabilities: caps});
let retryIteration = 0;
let lastError = null;

const condFn = async () => {
try {
retryIteration++;
await this.jwproxy.command('/session', 'POST', {desiredCapabilities: caps});
return true;
} catch (error) {
lastError = error;
log.warn(`Could not start WinAppDriver session error = '${error}', attempt = '${retryIteration}' from '${this.createSessionRetry}'`);
return false;
}
};

try {
await waitForCondition(condFn, {
waitMs: createSessionTimeout,
intervalMs: 500
});
} catch (timeoutError) {
log.debug(timeoutError);
if (lastError) {
throw (lastError);
}
throw (timeoutError);
}
}

async stop (emitStates = true) {
Expand Down Expand Up @@ -202,5 +237,5 @@ WinAppDriver.STATE_STARTING = 'starting';
WinAppDriver.STATE_ONLINE = 'online';
WinAppDriver.STATE_STOPPING = 'stopping';

export { WinAppDriver, DEFAULT_WAD_HOST, DEFAULT_WAD_PORT};
export { WinAppDriver, DEFAULT_WAD_HOST, DEFAULT_WAD_PORT };
export default WinAppDriver;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"watch": "gulp watch",
"coverage": "gulp coveralls",
"precommit-msg": "echo 'Pre-commit checks...' && exit 0",
"precommit-test": "REPORTER=dot gulp once",
"precommit-test": "env REPORTER=dot bash -c 'gulp once'",
"lint": "gulp lint",
"lint:fix": "gulp lint --fix",
"install": "node install-npm.js"
Expand Down

0 comments on commit 07b8e4c

Please sign in to comment.