roku-test-automation
Advanced tools
Comparing version 1.0.33 to 1.0.34
@@ -15,4 +15,4 @@ import { RokuDevice } from './RokuDevice'; | ||
sendKeyPressSequence(keys: ECPKeys[], wait?: number): Promise<void>; | ||
sendLaunchChannel(channelId?: string, params?: {}, verifyLaunch?: boolean): Promise<void>; | ||
sendLaunchChannel(params?: {}, verifyLaunch?: boolean, channelId?: string): Promise<void>; | ||
getActiveApp(): Promise<ActiveAppResponse>; | ||
} |
@@ -131,6 +131,6 @@ "use strict"; | ||
}; | ||
ECP.prototype.sendLaunchChannel = function (channelId, params, verifyLaunch) { | ||
if (channelId === void 0) { channelId = ''; } | ||
ECP.prototype.sendLaunchChannel = function (params, verifyLaunch, channelId) { | ||
if (params === void 0) { params = {}; } | ||
if (verifyLaunch === void 0) { verifyLaunch = true; } | ||
if (channelId === void 0) { channelId = ''; } | ||
var _a, _b, _c; | ||
@@ -137,0 +137,0 @@ return __awaiter(this, void 0, void 0, function () { |
import { RokuDevice } from './RokuDevice'; | ||
import { ConfigOptions } from './types/ConfigOptions'; | ||
import { KeyPathBaseTypes } from './types/OnDeviceComponentRequest'; | ||
import { KeyPathBaseTypes, OnDeviceComponentBaseResponse } from './types/OnDeviceComponentRequest'; | ||
export declare class OnDeviceComponent { | ||
private debugLog; | ||
private static readonly version; | ||
@@ -10,8 +11,15 @@ private callbackListenPort?; | ||
private client; | ||
private handshakeComplete; | ||
private sentRequests; | ||
private app; | ||
private server?; | ||
private handshakeStatus?; | ||
private handshakePromise?; | ||
constructor(device: RokuDevice, config: ConfigOptions); | ||
getValueAtKeyPath(base: KeyPathBaseTypes, keyPath: string): Promise<any>; | ||
callFunc(base: KeyPathBaseTypes, keyPath: string, funcName: string, funcParams?: any[]): Promise<{ | ||
value: any; | ||
} & OnDeviceComponentBaseResponse>; | ||
getValueAtKeyPath(base: KeyPathBaseTypes, keyPath: string): Promise<{ | ||
found: boolean; | ||
value: any; | ||
} & OnDeviceComponentBaseResponse>; | ||
getValuesAtKeyPaths(requests: { | ||
@@ -22,9 +30,17 @@ [key: string]: { | ||
}; | ||
}): Promise<any>; | ||
setValueAtKeyPath(base: KeyPathBaseTypes, keyPath: string, value: any): Promise<any>; | ||
}): Promise<{ | ||
[key: string]: any; | ||
found: boolean; | ||
value: any; | ||
} & OnDeviceComponentBaseResponse>; | ||
observeField(base: KeyPathBaseTypes, keyPath: string, matchValue?: any, matchBase?: KeyPathBaseTypes, matchKeyPath?: string): Promise<{ | ||
value: any; | ||
} & OnDeviceComponentBaseResponse>; | ||
setValueAtKeyPath(base: KeyPathBaseTypes, keyPath: string, value: any): Promise<OnDeviceComponentBaseResponse>; | ||
private sendHandShakeRequest; | ||
private sendRequest; | ||
setupConnections(): Promise<void>; | ||
private sendRequestCore; | ||
private startServer; | ||
shutdown(): void; | ||
private setupExpress; | ||
} |
@@ -41,8 +41,7 @@ "use strict"; | ||
var express = require("express"); | ||
var OnDeviceComponentRequest_1 = require("./types/OnDeviceComponentRequest"); | ||
var utils = require("./utils"); | ||
var OnDeviceComponent = /** @class */ (function () { | ||
function OnDeviceComponent(device, config) { | ||
this.debugLog = false; | ||
this.client = udp.createSocket('udp4'); | ||
this.handshakeComplete = false; | ||
this.sentRequests = {}; | ||
@@ -53,2 +52,23 @@ this.app = this.setupExpress(); | ||
} | ||
OnDeviceComponent.prototype.callFunc = function (base, keyPath, funcName, funcParams) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var result; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.sendRequest({ | ||
type: 'callFunc', | ||
args: { | ||
base: base, | ||
keyPath: keyPath, | ||
funcName: funcName, | ||
funcParams: funcParams | ||
} | ||
})]; | ||
case 1: | ||
result = _a.sent(); | ||
return [2 /*return*/, result.body]; | ||
} | ||
}); | ||
}); | ||
}; | ||
OnDeviceComponent.prototype.getValueAtKeyPath = function (base, keyPath) { | ||
@@ -91,2 +111,39 @@ return __awaiter(this, void 0, void 0, function () { | ||
}; | ||
OnDeviceComponent.prototype.observeField = function (base, keyPath, matchValue, matchBase, matchKeyPath) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var keyPathParts, args, match, result; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
keyPathParts = keyPath.split('.'); | ||
args = { | ||
base: base, | ||
field: keyPathParts.pop(), | ||
keyPath: keyPathParts.join('.') | ||
}; | ||
if (matchValue !== undefined) { | ||
if (matchBase === undefined) { | ||
matchBase = base; | ||
} | ||
if (matchKeyPath === undefined) { | ||
matchKeyPath = keyPath; | ||
} | ||
match = { | ||
value: matchValue, | ||
base: matchBase, | ||
keyPath: matchKeyPath | ||
}; | ||
args.match = match; | ||
} | ||
return [4 /*yield*/, this.sendRequest({ | ||
type: 'observeField', | ||
args: args | ||
})]; | ||
case 1: | ||
result = _a.sent(); | ||
return [2 /*return*/, result.body]; | ||
} | ||
}); | ||
}); | ||
}; | ||
OnDeviceComponent.prototype.setValueAtKeyPath = function (base, keyPath, value) { | ||
@@ -117,33 +174,61 @@ return __awaiter(this, void 0, void 0, function () { | ||
OnDeviceComponent.prototype.sendHandShakeRequest = function () { | ||
var _a, _b; | ||
var _this = this; | ||
if (!this.handshakePromise) { | ||
this.handshakePromise = Promise.resolve().then(function () { return __awaiter(_this, void 0, void 0, function () { | ||
var retryCount, result, e_1; | ||
var _a, _b; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
this.handshakeStatus = 'running'; | ||
retryCount = 10; | ||
_c.label = 1; | ||
case 1: | ||
if (!(retryCount > 0)) return [3 /*break*/, 6]; | ||
_c.label = 2; | ||
case 2: | ||
_c.trys.push([2, 4, , 5]); | ||
return [4 /*yield*/, this.sendRequestCore({ | ||
type: 'handshake', | ||
args: { | ||
version: OnDeviceComponent.version, | ||
logLevel: (_b = (_a = this.config.device.odc) === null || _a === void 0 ? void 0 : _a.logLevel) !== null && _b !== void 0 ? _b : 'info' | ||
} | ||
}, 1000)]; | ||
case 3: | ||
result = _c.sent(); | ||
this.handshakeStatus = 'complete'; | ||
return [2 /*return*/, result.body]; | ||
case 4: | ||
e_1 = _c.sent(); | ||
retryCount--; | ||
if (retryCount && this.debugLog) | ||
console.log('Send handshake failed. Retrying'); | ||
return [3 /*break*/, 5]; | ||
case 5: return [3 /*break*/, 1]; | ||
case 6: | ||
this.handshakeStatus = 'failed'; | ||
throw new Error('Handshake failed'); | ||
} | ||
}); | ||
}); }); | ||
} | ||
return this.handshakePromise; | ||
}; | ||
OnDeviceComponent.prototype.sendRequest = function (request, timeoutMilliseconds) { | ||
if (timeoutMilliseconds === void 0) { timeoutMilliseconds = 5000; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var retryCount, result, e_1; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
retryCount = 5; | ||
_c.label = 1; | ||
if (!(this.handshakeStatus !== 'complete')) return [3 /*break*/, 2]; | ||
if (this.handshakeStatus === 'failed') { | ||
throw new Error('Can not continue as handshake was not successful'); | ||
} | ||
return [4 /*yield*/, this.sendHandShakeRequest()]; | ||
case 1: | ||
if (!(retryCount > 0)) return [3 /*break*/, 6]; | ||
_c.label = 2; | ||
case 2: | ||
_c.trys.push([2, 4, , 5]); | ||
return [4 /*yield*/, this.sendRequest({ | ||
type: 'handshake', | ||
args: { | ||
version: OnDeviceComponent.version, | ||
logLevel: (_b = (_a = this.config.device.odc) === null || _a === void 0 ? void 0 : _a.logLevel) !== null && _b !== void 0 ? _b : 'info' | ||
} | ||
}, 1000)]; | ||
case 3: | ||
result = _c.sent(); | ||
return [2 /*return*/, result.body]; | ||
case 4: | ||
e_1 = _c.sent(); | ||
retryCount--; | ||
if (retryCount) | ||
console.log('Send handshake failed. Retrying'); | ||
return [3 /*break*/, 5]; | ||
case 5: return [3 /*break*/, 1]; | ||
case 6: throw new Error('Handshake failed'); | ||
_a.sent(); | ||
_a.label = 2; | ||
case 2: return [4 /*yield*/, this.sendRequestCore(request, timeoutMilliseconds)]; | ||
case 3: return [2 /*return*/, _a.sent()]; | ||
} | ||
@@ -153,14 +238,11 @@ }); | ||
}; | ||
OnDeviceComponent.prototype.sendRequest = function (request, timeoutMilliseconds) { | ||
OnDeviceComponent.prototype.sendRequestCore = function (request, timeoutMilliseconds) { | ||
if (timeoutMilliseconds === void 0) { timeoutMilliseconds = 5000; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var requestId, formattedRequest, promise; | ||
var requestId, formattedRequest, promise, body; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.setupConnections()]; | ||
case 0: return [4 /*yield*/, this.startServer()]; | ||
case 1: | ||
_a.sent(); | ||
if (request.type !== OnDeviceComponentRequest_1.RequestEnum[OnDeviceComponentRequest_1.RequestEnum.handshake] && !this.handshakeComplete) { | ||
throw new Error("Handshake not complete. Can't continue"); | ||
} | ||
requestId = utils.randomStringGenerator(); | ||
@@ -186,3 +268,6 @@ formattedRequest = { | ||
this.sentRequests[requestId] = request; | ||
this.client.send(JSON.stringify(formattedRequest), 9000, this.device.ip, function (err) { | ||
body = JSON.stringify(formattedRequest); | ||
if (this.debugLog) | ||
console.log("Sending request to " + this.device.ip + " with body: " + body); | ||
this.client.send(body, 9000, this.device.ip, function (err) { | ||
if (err) { | ||
@@ -192,3 +277,3 @@ throw err; | ||
}); | ||
return [4 /*yield*/, utils.promiseTimeout(promise, timeoutMilliseconds)]; | ||
return [4 /*yield*/, utils.promiseTimeout(promise, timeoutMilliseconds, request.type + " request " + requestId + " timed out after " + timeoutMilliseconds + "ms")]; | ||
case 2: return [2 /*return*/, _a.sent()]; | ||
@@ -199,26 +284,23 @@ } | ||
}; | ||
// Starts up express server and our connection to the OnDeviceComponent | ||
OnDeviceComponent.prototype.setupConnections = function () { | ||
// Starts up express server | ||
OnDeviceComponent.prototype.startServer = function () { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var callbackListenPort; | ||
var _this = this; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
// If we already have everything we need then don't want to rerun | ||
if (this.server) | ||
return [2 /*return*/]; | ||
callbackListenPort = (_a = this.config.server) === null || _a === void 0 ? void 0 : _a.callbackListenPort; | ||
if (!callbackListenPort) | ||
throw new Error('Config did not have a callback listen port'); | ||
this.server = this.app.listen(callbackListenPort, function () { | ||
console.log("Listening for callbacks on " + callbackListenPort); | ||
}); | ||
this.callbackListenPort = callbackListenPort; | ||
return [4 /*yield*/, this.sendHandShakeRequest()]; | ||
case 1: | ||
_b.sent(); | ||
this.handshakeComplete = true; | ||
return [2 /*return*/]; | ||
if (this.server) { | ||
return [2 /*return*/]; | ||
} | ||
callbackListenPort = (_a = this.config.server) === null || _a === void 0 ? void 0 : _a.callbackListenPort; | ||
if (!callbackListenPort) | ||
throw new Error('Config did not have a callback listen port'); | ||
if (this.debugLog) | ||
console.log("Starting callback server"); | ||
this.server = this.app.listen(callbackListenPort, function () { | ||
if (_this.debugLog) | ||
console.log("Listening for callbacks on " + callbackListenPort); | ||
}); | ||
this.callbackListenPort = callbackListenPort; | ||
return [2 /*return*/]; | ||
}); | ||
@@ -242,2 +324,4 @@ }); | ||
if (request) { | ||
if (_this.debugLog) | ||
console.log("Server received response", req.body); | ||
(_a = request.callback) === null || _a === void 0 ? void 0 : _a.call(request, req); | ||
@@ -244,0 +328,0 @@ res.send('OK'); |
@@ -9,9 +9,10 @@ /// <reference types="mocha" /> | ||
private screenshotFormat; | ||
private needle; | ||
constructor(ip: string, password: string, screenshotFormat?: ScreenshotFormat); | ||
setDebugProxy(debugProxy: string): void; | ||
sendECP(path: string, params?: {}, body?: needle.BodyData): Promise<needle.NeedleResponse>; | ||
sendECP(path: string, params?: object, body?: needle.BodyData): Promise<needle.NeedleResponse>; | ||
/** | ||
* @param outputFilePath - Where to output the generated screenshot. Extension is automatically appended based on what type of screenshotFormat you have specified for this device | ||
*/ | ||
getScreenshot(outputFilePath: string): Promise<void>; | ||
getScreenshot(outputFilePath: string): Promise<string>; | ||
getTestScreenshot(contextOrSuite: Mocha.Context | Mocha.Suite): Promise<void>; | ||
@@ -18,0 +19,0 @@ private generateScreenshot; |
@@ -40,4 +40,4 @@ "use strict"; | ||
var needle = require("needle"); | ||
var querystring = require("needle/lib/querystring"); | ||
var utils = require("./utils"); | ||
var query_string_1 = require("query-string"); | ||
var RokuDevice = /** @class */ (function () { | ||
@@ -47,2 +47,3 @@ function RokuDevice(ip, password, screenshotFormat) { | ||
this.debugProxy = ''; | ||
this.needle = needle; | ||
this.ip = ip; | ||
@@ -63,8 +64,8 @@ this.password = password; | ||
if (params && Object.keys(params).length) { | ||
url = url.replace(/\?.*|$/, '?' + query_string_1.stringify(params)); | ||
url = url.replace(/\?.*|$/, '?' + querystring.build(params)); | ||
} | ||
if (!(body !== undefined)) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, needle('post', url, body, this.getOptions())]; | ||
return [4 /*yield*/, this.needle('post', url, body, this.getOptions())]; | ||
case 1: return [2 /*return*/, _a.sent()]; | ||
case 2: return [4 /*yield*/, needle('get', url, this.getOptions())]; | ||
case 2: return [4 /*yield*/, this.needle('get', url, this.getOptions())]; | ||
case 3: return [2 /*return*/, _a.sent()]; | ||
@@ -86,5 +87,3 @@ } | ||
return [4 /*yield*/, this.saveScreenshot(outputFilePath)]; | ||
case 2: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
case 2: return [2 /*return*/, _a.sent()]; | ||
} | ||
@@ -119,3 +118,3 @@ }); | ||
options.multipart = true; | ||
return [4 /*yield*/, needle('post', url, data, options)]; | ||
return [4 /*yield*/, this.needle('post', url, data, options)]; | ||
case 1: return [2 /*return*/, _a.sent()]; | ||
@@ -138,9 +137,9 @@ } | ||
url = "http://" + this.ip + "/pkgs/dev" + ext; | ||
return [4 /*yield*/, needle('get', url, options)]; | ||
return [4 /*yield*/, this.needle('get', url, options)]; | ||
case 2: | ||
result = _a.sent(); | ||
if (result.statusCode !== 200) { | ||
throw new Error("Could not download screenshot at " + url); | ||
throw new Error("Could not download screenshot at " + url + ". Make sure you have the correct screenshot format in your config"); | ||
} | ||
return [2 /*return*/]; | ||
return [2 /*return*/, options.output]; | ||
} | ||
@@ -147,0 +146,0 @@ }); |
@@ -24,5 +24,6 @@ import * as express from 'express'; | ||
args: object; | ||
callback?: OnDeviceComponentRequestCallback; | ||
callback?: (req: express.Request) => void; | ||
} | ||
declare type OnDeviceComponentRequestCallback = (req: express.Request) => void; | ||
export {}; | ||
export interface OnDeviceComponentBaseResponse { | ||
success: boolean; | ||
} |
@@ -18,3 +18,3 @@ import * as Mocha from 'mocha'; | ||
export declare function sleep(milliseconds: number): Promise<unknown>; | ||
export declare function promiseTimeout<T>(promise: Promise<T>, milliseconds: number): Promise<T>; | ||
export declare function promiseTimeout<T>(promise: Promise<T>, milliseconds: number, message?: string): Promise<T>; | ||
export declare function makeError(name: string, message: string): Error; | ||
@@ -25,1 +25,2 @@ export declare function getTestTitlePath(contextOrSuite: Mocha.Context | Mocha.Suite): string[]; | ||
export declare function randomStringGenerator(length?: number): any; | ||
export declare function addRandomPostfix(message: string, length?: number): string; |
@@ -102,6 +102,9 @@ "use strict"; | ||
exports.sleep = sleep; | ||
function promiseTimeout(promise, milliseconds) { | ||
function promiseTimeout(promise, milliseconds, message) { | ||
var timeout = new Promise(function (resolve, reject) { | ||
setTimeout(function () { | ||
reject('Timed out after ' + milliseconds + 'ms.'); | ||
if (message === undefined) { | ||
message = 'Timed out after ' + milliseconds + 'ms.'; | ||
} | ||
reject(message); | ||
}, milliseconds); | ||
@@ -163,1 +166,6 @@ }); | ||
exports.randomStringGenerator = randomStringGenerator; | ||
function addRandomPostfix(message, length) { | ||
if (length === void 0) { length = 2; } | ||
return message + "-" + randomStringGenerator(length); | ||
} | ||
exports.addRandomPostfix = addRandomPostfix; |
{ | ||
"name": "roku-test-automation", | ||
"version": "1.0.33", | ||
"version": "1.0.34", | ||
"description": "Helps with automating functional tests", | ||
@@ -29,7 +29,6 @@ "main": "dist/index.js", | ||
"fs-extra": "^7.0.1", | ||
"http-proxy-middleware": "^1.0.3", | ||
"needle": "^2.3.2", | ||
"path": "^0.12.7", | ||
"query-string": "^6.12.1", | ||
"ts-interface-checker": "^0.1.10" | ||
"ts-interface-checker": "^0.1.10", | ||
"http-proxy-middleware": "^1.0.3" | ||
}, | ||
@@ -36,0 +35,0 @@ "devDependencies": { |
@@ -19,5 +19,5 @@ { | ||
"ecp": { | ||
"keyPressDelay": 1000 | ||
"keyPressDelay": 300 | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
86632
6
1314
- Removedquery-string@^6.12.1
- Removeddecode-uri-component@0.2.2(transitive)
- Removedfilter-obj@1.1.0(transitive)
- Removedquery-string@6.14.1(transitive)
- Removedsplit-on-first@1.1.0(transitive)
- Removedstrict-uri-encode@2.0.0(transitive)