diff --git a/docs/server-setup.md b/docs/server-setup.md index 296722d2f..471019f90 100644 --- a/docs/server-setup.md +++ b/docs/server-setup.md @@ -55,13 +55,13 @@ To connect to a running instance of a standalone Selenium Server, set this optio - `seleniumAddress` - Connect to a running instance of a standalone Selenium Server. The address will be a URL. -Please note that if you set seleniumAddress, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `browserstackUser`, `browserstackKey`, `sauceUser` and `sauceKey` will be ignored. +Please note that if you set seleniumAddress, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `browserstackUser`, `browserstackKey`, `sauceUser`, `sauceKey`, `lambdaUsername` and `lambdaAccessKey` will be ignored. Remote Selenium Server ---------------------- -To run your tests against a remote Selenium Server, you will need an account with a service that hosts the server (and the browser drivers). Protractor has built in support for [BrowserStack](https://www.browserstack.com) , [Sauce Labs](http://www.saucelabs.com) and [TestObject](https://www.testobject.com). +To run your tests against a remote Selenium Server, you will need an account with a service that hosts the server (and the browser drivers). Protractor has built in support for [BrowserStack](https://www.browserstack.com) , [Sauce Labs](http://www.saucelabs.com) and [TestObject](https://www.testobject.com) , [TestObject](https://www.testobject.com) and [LambdaTest](https://www.lambdatest.com). **Using TestObject as remote Selenium Server** @@ -69,7 +69,7 @@ In your config file, set these options: - `testobjectUser` - The username for your TestObject account. - `testobjectKey` - The key for your TestObject account. -Please note that if you set `testobjectUser` and `testobjectKey`, the settings for `kobitonUser`, `kobitonKey`, `browserstackUser`, `browserstackKey`, `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `sauceUser` and `sauceKey` will be ignored. +Please note that if you set `testobjectUser` and `testobjectKey`, the settings for `kobitonUser`, `kobitonKey`, `browserstackUser`, `browserstackKey`, `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `sauceUser`, `sauceKey`, `lambdaUsername` and `lambdaAccessKey` will be ignored. **Using Kobiton as remote Selenium Server** @@ -77,7 +77,7 @@ In your config file, set these options: - `kobitonUser` - The username for your Kobiton account. - `kobitonKey` - The API key from your Kobiton account. -Please note that if you set `kobitonUser` and `kobitonKey`, the settings for `browserstackUser`, `browserstackKey`, `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `sauceUser` and `sauceKey` will be ignored. +Please note that if you set `kobitonUser` and `kobitonKey`, the settings for `browserstackUser`, `browserstackKey`, `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `sauceUser`, `sauceKey`, `lambdaUsername` and `lambdaAccessKey` will be ignored. **Using BrowserStack as remote Selenium Server** @@ -85,7 +85,7 @@ In your config file, set these options: - `browserstackUser` - The username for your BrowserStack account. - `browserstackKey` - The key for your BrowserStack account. -Please note that if you set `browserstackUser` and `browserstackKey`, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `sauceUser` and `sauceKey` will be ignored. +Please note that if you set `browserstackUser` and `browserstackKey`, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `sauceUser`, `sauceKey`, `lambdaUsername` and `lambdaAccessKey` will be ignored. You can optionally set the `name` property in a capability in order to give the jobs a name on the server. Otherwise they will just be allotted a random hash. @@ -95,10 +95,17 @@ In your config file, set these options: - `sauceUser` - The username for your Sauce Labs account. - `sauceKey` - The key for your Sauce Labs account. -Please note that if you set `sauceUser` and `sauceKey`, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `browserstackUser` and `browserstackKey` will be ignored. +Please note that if you set `sauceUser` and `sauceKey`, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `browserstackUser`, `browserstackKey`, `lambdaUsername` and `lambdaAccessKey` will be ignored. You can optionally set the `name` property in a capability in order to give the jobs a name on the server. Otherwise they will just be called `Unnamed Job`. +**Using LambdaTest as remote Selenium Server** + +In your config file, set these options: + - `lambdaUsername` - The username for your LambdaTest account. + - `lambdaAccessKey` - The access key for your LambdaTest account. + +Please note that if you set `lambdaUsername` and `lambdaAccessKey`, the settings for `seleniumServerJar`, `seleniumPort`, `seleniumArgs`, `testobjectUser`, `testobjectKey`, `sauceUser`, `sauceKey`, `browserstackUser`, `browserstackKey`, `kobitonUser` and `kobitonKey` will be ignored. Connecting Directly to Browser Drivers -------------------------------------- diff --git a/lib/cli.ts b/lib/cli.ts index 225dd728f..61f0b01c6 100644 --- a/lib/cli.ts +++ b/lib/cli.ts @@ -55,6 +55,8 @@ let allowedNames = [ 'kobitonKey', 'testobjectUser', 'testobjectKey', + 'lambdaUsername', + 'lambdaAccessKey', 'directConnect', 'firefoxPath', 'noGlobals', diff --git a/lib/config.ts b/lib/config.ts index c04849088..d93e3cec3 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -17,7 +17,9 @@ export interface Config { // 3. sauceUser/sauceKey - to use remote Selenium Servers via Sauce Labs. // 4. browserstackUser/browserstackKey - to use remote Selenium Servers via // BrowserStack. - // 5. directConnect - to connect directly to the browser Drivers. + // 5. lambdaUsername/lambdaAccessKey - to use remote Selenium Servers via + // Lambdatest. + // 6. directConnect - to connect directly to the browser Drivers. // This option is only available for Firefox and Chrome. // // ---- 1. To start a standalone Selenium Server locally --------------------- @@ -220,7 +222,22 @@ export interface Config { */ browserstackProxy?: string; - // ---- 7. To connect directly to Drivers ------------------------------------ + // ---- 7. To use remote browsers via LambdaTest --------------------------- + + /** + * If lambdaUsername and lambdaAccessKey are specified, kobitonUser, kobitonKey, testobjectUser, + * testojbectKey, browserstackUser, browserStackKey and seleniumServerJar will be ignored. The + * tests will be run remotely using LambdaTest. + */ + lambdaUsername?: string; + /** + * If lambdaUsername and lambdaAccessKey are specified, kobitonUser, kobitonKey, testobjectUser, + * testojbectKey, browserStackUser, browserStackKey and seleniumServerJar will be ignored. The + * tests will be run remotely using LambdaTest. + */ + lambdaAccessKey?: string; + + // ---- 8. To connect directly to Drivers ------------------------------------ /** * If true, Protractor will connect directly to the browser Drivers diff --git a/lib/driverProviders/index.ts b/lib/driverProviders/index.ts index 25fcabcf6..610a18e46 100644 --- a/lib/driverProviders/index.ts +++ b/lib/driverProviders/index.ts @@ -8,6 +8,7 @@ export * from './mock'; export * from './sauce'; export * from './testObject'; export * from './kobiton'; +export * from './lambdaTest'; import {AttachSession} from './attachSession'; @@ -20,6 +21,7 @@ import {Mock} from './mock'; import {Sauce} from './sauce'; import {TestObject} from './testObject'; import {Kobiton} from './kobiton'; +import {LambdaTest} from './lambdaTest'; import {Config} from '../config'; import {Logger} from '../logger'; @@ -52,6 +54,9 @@ export let buildDriverProvider = (config: Config): DriverProvider => { } else if (config.sauceUser && config.sauceKey) { driverProvider = new Sauce(config); logWarnings('sauce', config); + } else if (config.lambdaUsername && config.lambdaAccessKey) { + driverProvider = new LambdaTest(config); + logWarnings('lambdaTest', config); } else if (config.seleniumServerJar) { driverProvider = new Local(config); logWarnings('local', config); @@ -103,6 +108,12 @@ export let logWarnings = (providerType: string, config: Config): void => { if ('sauce' !== providerType && config.sauceKey) { warnList.push('sauceKey'); } + if ('lambdaTest' !== providerType && config.lambdaUsername) { + warnList.push('lambdaUsername'); + } + if ('lambdaTest' !== providerType && config.lambdaAccessKey) { + warnList.push('lambdaAccessKey'); + } if ('local' !== providerType && config.seleniumServerJar) { warnList.push('seleniumServerJar'); } diff --git a/lib/driverProviders/lambdaTest.ts b/lib/driverProviders/lambdaTest.ts new file mode 100644 index 000000000..4c31fdece --- /dev/null +++ b/lib/driverProviders/lambdaTest.ts @@ -0,0 +1,64 @@ +/* + * This is an implementation of the LambdaTest Driver Provider. + * It is responsible for setting up the account object, tearing + * it down, and setting up the driver correctly. + */ +import {WebDriver} from 'selenium-webdriver'; +import * as util from 'util'; + +import {Config} from '../config'; +import {Logger} from '../logger'; + +import {DriverProvider} from './driverProvider'; + +Logger.setWrite(2, 'lambda_protractor.log'); +const lambdaRestClient = require('@lambdatest/node-rest-client'); +let logger = new Logger('lambdatest'); + +export class LambdaTest extends DriverProvider { + lambdaAutomationClient: any; + + constructor(config: Config) { + super(config); + } + + /** + * Hook to update the LambdaTest job status. + * @public + * @param {Object} update + * @return {Promise} A promise that will resolve when the update is complete. + */ + updateJob(update: any): Promise { + let mappedDrivers = this.drivers_.map(async (driver: WebDriver) => { + const session = await driver.getSession(); + const statusObj = {status_ind: update.passed ? 'passed' : 'failed'}; + this.lambdaAutomationClient.updateSessionById(session.getId(), statusObj, (error: Error) => { + if (error) { + throw new Error( + 'Error while updating LambdaTest passed/failed status: ' + util.inspect(error)); + } + }); + }); + return Promise.all(mappedDrivers); + } + + /** + * Configure and launch (if applicable) the object's environment. + * @return {promise} A promise which will resolve when the environment is + * ready to test. + */ + protected async setupDriverEnv(): Promise { + this.config_.capabilities['user'] = this.config_.lambdaUsername; + this.config_.capabilities['accessKey'] = this.config_.lambdaAccessKey; + this.config_.seleniumAddress = 'https://hub.lambdatest.com/wd/hub'; + this.lambdaAutomationClient = lambdaRestClient.AutomationClient( + {username: this.config_.lambdaUsername, accessKey: this.config_.lambdaAccessKey}); + + // Append filename to capabilities.name so that it's easier to identify + // tests. + this.config_.capabilities.name = this.config_.capabilities.name || ''; + this.config_.capabilities.name += ':' + this.config_.specs.toString().replace(/^.*[\\\/]/, ''); + + logger.info(`Using LambdaTest selenium server at ${this.config_.seleniumAddress}`); + } +} diff --git a/package-lock.json b/package-lock.json index ee79a6aba..091d207e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,15 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@lambdatest/node-rest-client": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lambdatest/node-rest-client/-/node-rest-client-1.0.0.tgz", + "integrity": "sha512-Ye9kXZOmKaanywMGMVlI87Nah1xg4ayPGygzbJoHCGuB+KuEjxAWpkVyabb0p1fuBEr1P6W+gV32NPNG4IIkUQ==", + "requires": { + "request": "^2.88.0", + "winston": "^3.2.1" + } + }, "@types/chalk": { "version": "0.4.31", "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-0.4.31.tgz", @@ -955,11 +964,19 @@ "object-visit": "^1.0.0" } }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -967,8 +984,16 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } }, "color-support": { "version": "1.1.3", @@ -976,11 +1001,24 @@ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true }, + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" + }, "colors": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", - "dev": true + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } }, "combined-stream": { "version": "1.0.7", @@ -1317,6 +1355,16 @@ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + }, "diff": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.3.tgz", @@ -1434,6 +1482,14 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "requires": { + "env-variable": "0.0.x" + } + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1449,6 +1505,11 @@ "once": "^1.4.0" } }, + "env-variable": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", + "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1853,6 +1914,16 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" + }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -3798,6 +3869,14 @@ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true }, + "kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "requires": { + "colornames": "^1.1.1" + } + }, "last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", @@ -3892,8 +3971,7 @@ "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash._basecopy": { "version": "3.0.1", @@ -4060,6 +4138,25 @@ } } }, + "logform": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", + "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "loglevel": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", @@ -4687,6 +4784,11 @@ "wrappy": "1" } }, + "one-time": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", + "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -5495,6 +5597,21 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -5724,8 +5841,7 @@ "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, "static-extend": { "version": "0.1.2", @@ -5910,6 +6026,11 @@ "execa": "^0.7.0" } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -6082,6 +6203,11 @@ } } }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", @@ -6787,6 +6913,88 @@ "string-width": "^2.1.1" } }, + "winston": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", + "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", + "requires": { + "async": "^2.6.1", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^2.1.1", + "one-time": "0.0.4", + "readable-stream": "^3.1.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.3.0" + }, + "dependencies": { + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "requires": { + "lodash": "^4.17.11" + } + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "winston-transport": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", + "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", + "requires": { + "readable-stream": "^2.3.6", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", diff --git a/package.json b/package.json index bccd60600..25e82ca4b 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ ], "author": "Julie Ralph ", "dependencies": { + "@lambdatest/node-rest-client": "^1.0.0", "blocking-proxy": "^1.0.0", "browserstack": "^1.5.1", "chalk": "^1.1.3", diff --git a/scripts/errorTest.js b/scripts/errorTest.js index 050d4d2d6..b9d62a6db 100644 --- a/scripts/errorTest.js +++ b/scripts/errorTest.js @@ -35,6 +35,14 @@ messages = ['Invalid username or password', 'Process exited with error code ' + exitCodes.BrowserError.CODE]; checkLogs(output, messages); +// assert authentication error for LambdaTest +runProtractor = spawn('node', ['bin/protractor', 'spec/errorTest/lambdaTestAuthentication.js']); +output = runProtractor.stdout.toString(); +messages = [ + 'Unauthorized, either Username or AccessKey is invalid', 'Process exited with error code ' + exitCodes.BrowserError.CODE +]; +checkLogs(output, messages); + // assert there is no capabilities in the config runProtractor = spawn('node', diff --git a/spec/driverProviderTest.js b/spec/driverProviderTest.js index a10237869..032c9ecb8 100644 --- a/spec/driverProviderTest.js +++ b/spec/driverProviderTest.js @@ -8,6 +8,8 @@ * - if you want to test saucelabs, test with --sauceUser and --sauceKey * - if you want to test browserstack driverProvider, test with --browserstackUser and --browserstackKey + * - if you want to test LambdaTest, test with --lambdaUsername and + --lambdaAccessKey * You should verify that there are no lingering processes when these tests * complete. */ @@ -20,6 +22,7 @@ const Hosted = require('../built/driverProviders/hosted').Hosted; const Local = require('../built/driverProviders/local').Local; const Sauce = require('../built/driverProviders/sauce').Sauce; const BrowserStack = require('../built/driverProviders/browserStack').BrowserStack; +const LambdaTest = require('../built/driverProviders/lambdaTest').LambdaTest; const testDriverProvider = async (driverProvider) => { await driverProvider.setupEnv(); @@ -143,3 +146,22 @@ if (argv.browserstackUser && argv.browserstackKey) { throw err; }); } + +if (argv.lambdaUsername && argv.lambdaAccessKey) { + const lambdatestConfig = { + lambdaUsername: argv.lambdaUsername, + lambdaAccessKey: argv.lambdaAccessKey, + capabilities: { + build: 'protractor-LambdaTest-spec', + name: 'protractor-LambdaTest-spec', + browserName: 'chrome', + } + }; + testDriverProvider(new LambdaTest(lambdatestConfig)). + then(() => { + console.log('lambdatest.dp working!'); + }, (err) => { + console.error('lambdatest.dp failed with', err); + throw err; + }); +} diff --git a/spec/errorTest/lambdaTestAuthentication.js b/spec/errorTest/lambdaTestAuthentication.js new file mode 100644 index 000000000..d6c5b01fb --- /dev/null +++ b/spec/errorTest/lambdaTestAuthentication.js @@ -0,0 +1,12 @@ +const env = require('../environment.js'); + +exports.config = { + lambdaUsername: 'foobar', + lambdaAccessKey: 'foobar', + SELENIUM_PROMISE_MANAGER: false, + framework: 'jasmine', + specs: ['../../example/example_spec.js'], + capabilities: {browserName: 'chrome'}, + baseUrl: env.baseUrl + '/ng1/', + jasmineNodeOpts: {defaultTimeoutInterval: 90000} +}; \ No newline at end of file