├── .babelrc ├── .eslintrc ├── .flowconfig ├── .gitignore ├── README.md ├── interfaces ├── chai.js ├── mocha.js └── webdriver.js ├── package.json ├── src ├── lib │ ├── DriverBuilder.js │ └── driver-utils.js └── pageobjects │ ├── BasePage.js │ ├── HomePage.js │ └── SearchResultsPage.js └── test ├── AcceptanceTest.js └── mocha.opts /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "targets": { 5 | "node": "current" 6 | } 7 | }] 8 | ], 9 | "plugins": [ 10 | "transform-flow-strip-types", 11 | "transform-object-rest-spread" 12 | ], 13 | "retainLines": true, 14 | "sourceMaps": "both" 15 | } 16 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended", "standard", "plugin:flowtype/recommended"], 3 | "parser": "babel-eslint", 4 | "plugins": [ 5 | "flowtype" 6 | ], 7 | "env": { 8 | "node": true, 9 | "mocha": true 10 | }, 11 | "parserOptions": { 12 | "ecmaVersion": 8, 13 | "sourceType": "module" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [include] 2 | ./node_modules 3 | 4 | [libs] 5 | ./interfaces 6 | 7 | [options] 8 | suppress_comment= \\(.\\|\n\\)*\\$FlowIssue 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | logs 3 | *.log 4 | npm-debug.log* 5 | node_modules 6 | .npm 7 | .node_repl_history 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Note: Babel transforms for async/await have been removed; this boilerplate is compatible with Node >=7.6.0 2 | 3 | # webdriver-mocha-async-await-example 4 | 5 | This is an example of using Mocha, Selenium WebDriver and Babel together to provide async / await syntax to browser automation tests. Additionally, the page objects conventions model how Airware's test automation team structures their tests. 6 | 7 | We've also added Flowtype annotations and a webdriver type interface like the one we use internally. 8 | 9 | Originally presented at the Selenium Meetup in SF on 10-19-16. 10 | 11 | [Video of the Meetup](https://www.youtube.com/watch?v=BTpMB2-8qMM) 12 | 13 | [Slides from the Meetup](http://www.slideshare.net/MekSrunyuStittri/endtoend-test-automation-with-nodejs-one-year-later) 14 | 15 | Prequisites include Java, NodeJs, Chrome browser. 16 | 17 | To start the Selenium server: `npm start` 18 | 19 | To run the acceptance test suite: `npm test` 20 | 21 | Lint: `npm run lint` 22 | Flow type checking: `npm run flow` 23 | 24 | **Questions?** You can email the test automation team at cclayman@airware.com or mstittri@airware.com, or file an issue. Contributions welcome. 25 | -------------------------------------------------------------------------------- /interfaces/chai.js: -------------------------------------------------------------------------------- 1 | declare type ChaiAssert = { 2 | (expression: any, message?: string): void, 3 | fail(actual?: any, expected?: any, msg?: string, operator?: string): void, 4 | ok(val: any, msg?: string): void, 5 | isOk(val: any, msg?: string): void, 6 | notOk(val: any, msg?: string): void, 7 | isNotOk(val: any, msg?: string): void, 8 | equal(act: any, exp: any, msg?: string): void, 9 | notEqual(act: any, exp: any, msg?: string): void, 10 | strictEqual(act: any, exp: any, msg?: string): void, 11 | notStrictEqual(act: any, exp: any, msg?: string): void, 12 | deepEqual(act: any, exp: any, msg?: string): void, 13 | notDeepEqual(act: any, exp: any, msg?: string): void, 14 | isTrue(val: any, msg?: string): void, 15 | isFalse(val: any, msg?: string): void, 16 | isNull(val: any, msg?: string): void, 17 | isNotNull(val: any, msg?: string): void, 18 | isUndefined(val: any, msg?: string): void, 19 | isAtMost(act: number, exp: number, msg?: string): void, 20 | isAtLeast(act: number, exp: number, msg?: string): void, 21 | isDefined(val: any, msg?: string): void, 22 | isNaN(val: any, msg?: string): void, 23 | isNotNaN(val: any, msg?: string): void, 24 | isAbove(val: number, abv: number, msg?: string): void, 25 | isBelow(val: number, blw: number, msg?: string): void, 26 | isFunction(val: any, msg?: string): void, 27 | isNotFunction(val: any, msg?: string): void, 28 | isObject(val: any, msg?: string): void, 29 | isNotObject(val: any, msg?: string): void, 30 | isArray(val: any, msg?: string): void, 31 | isNotArray(val: any, msg?: string): void, 32 | isString(val: any, msg?: string): void, 33 | isNotString(val: any, msg?: string): void, 34 | isNumber(val: any, msg?: string): void, 35 | isNotNumber(val: any, msg?: string): void, 36 | isBoolean(val: any, msg?: string): void, 37 | isNotBoolean(val: any, msg?: string): void, 38 | typeOf(val: any, type: string, msg?: string): void, 39 | notTypeOf(val: any, type: string, msg?: string): void, 40 | instanceOf(val: any, type: Function, msg?: string): void, 41 | notInstanceOf(val: any, type: Function, msg?: string): void, 42 | include(exp: string | any[], inc: any, msg?: string): void, 43 | notInclude(exp: string | any[], inc: any, msg?: string): void, 44 | match(exp: any, re: RegExp, msg?: string): void, 45 | notMatch(exp: any, re: RegExp, msg?: string): void, 46 | property(obj: Object, prop: string, msg?: string): void, 47 | notProperty(obj: Object, prop: string, msg?: string): void, 48 | deepProperty(obj: Object, prop: string, msg?: string): void, 49 | notDeepProperty(obj: Object, prop: string, msg?: string): void, 50 | propertyVal(obj: Object, prop: string, val: any, msg?: string): void, 51 | propertyNotVal(obj: Object, prop: string, val: any, msg?: string): void, 52 | deepPropertyVal(obj: Object, prop: string, val: any, msg?: string): void, 53 | deepPropertyNotVal(obj: Object, prop: string, val: any, msg?: string): void, 54 | lengthOf(exp: any, len: number, msg?: string): void, 55 | // alias frenzy 56 | throw(fn: Function, msg?: string): void, 57 | throw(fn: Function, regExp: RegExp): void, 58 | throw(fn: Function, errType: Function, msg?: string): void, 59 | throw(fn: Function, errType: Function, regExp: RegExp): void, 60 | throws(fn: Function, msg?: string): void, 61 | throws(fn: Function, regExp: RegExp): void, 62 | throws(fn: Function, errType: Function, msg?: string): void, 63 | throws(fn: Function, errType: Function, regExp: RegExp): void, 64 | Throw(fn: Function, msg?: string): void, 65 | Throw(fn: Function, regExp: RegExp): void, 66 | Throw(fn: Function, errType: Function, msg?: string): void, 67 | Throw(fn: Function, errType: Function, regExp: RegExp): void, 68 | doesNotThrow(fn: Function, msg?: string): void, 69 | doesNotThrow(fn: Function, regExp: RegExp): void, 70 | doesNotThrow(fn: Function, errType: Function, msg?: string): void, 71 | doesNotThrow(fn: Function, errType: Function, regExp: RegExp): void, 72 | operator(val: any, operator: string, val2: any, msg?: string): void, 73 | closeTo(act: number, exp: number, delta: number, msg?: string): void, 74 | sameMembers(set1: any[], set2: any[], msg?: string): void, 75 | sameDeepMembers(set1: any[], set2: any[], msg?: string): void, 76 | includeMembers(superset: any[], subset: any[], msg?: string): void, 77 | oneOf(inList: any, list: any[], msg?: string): void, 78 | ifError(val: any, msg?: string): void, 79 | isExtensible(obj: Object, msg?: string): void, 80 | extensible(obj: Object, msg?: string): void, 81 | isNotExtensible(obj: Object, msg?: string): void, 82 | notExtensible(obj: Object, msg?: string): void, 83 | isSealed(obj: Object, msg?: string): void, 84 | sealed(obj: Object, msg?: string): void, 85 | isNotSealed(obj: Object, msg?: string): void, 86 | notSealed(obj: Object, msg?: string): void, 87 | isFrozen(obj: Object, msg?: string): void, 88 | frozen(obj: Object, msg?: string): void, 89 | isNotFrozen(obj: Object, msg?: string): void, 90 | notFrozen(obj: Object, msg?: string): void, 91 | jsonSchema(obj: Object, schema: JSON, msg?: string): void 92 | } 93 | 94 | declare type ChaiConfig = { 95 | includeStack: boolean 96 | } 97 | 98 | declare class ChaiAssertionError { 99 | constructor(message: string, _props?: any, ssf?: Function): ChaiAssertionError; 100 | name: string; 101 | message: string; 102 | showDiff: boolean; 103 | stack: string; 104 | } 105 | 106 | declare module 'chai' { 107 | declare var assert: ChaiAssert; 108 | declare function use(fn: (chai: any, utils: any) => void): any; 109 | declare var config: ChaiConfig; 110 | declare var AssertionError: typeof ChaiAssertionError; 111 | declare var tv4: Object 112 | } 113 | -------------------------------------------------------------------------------- /interfaces/mocha.js: -------------------------------------------------------------------------------- 1 | type TestFunction = (() => void | Promise | ((done: () => void) => void)); 2 | 3 | declare var describe : { 4 | (name: string, spec: () => void): void; 5 | only(description: string, spec: () => void): void; 6 | skip(description: string, spec: () => void): void; 7 | timeout(ms: number): void; 8 | }; 9 | 10 | declare var context : typeof describe; 11 | 12 | declare var it : { 13 | (name: string, spec: TestFunction): void; 14 | only(description: string, spec: TestFunction): void; 15 | skip(description: string, spec: TestFunction): void; 16 | timeout(ms: number): void; 17 | }; 18 | 19 | declare function before(method: TestFunction):void; 20 | declare function beforeEach(method: TestFunction):void; 21 | declare function after(method: TestFunction):void; 22 | declare function afterEach(method: TestFunction):void; 23 | -------------------------------------------------------------------------------- /interfaces/webdriver.js: -------------------------------------------------------------------------------- 1 | // Type definitions for Selenium WebDriverJS 2.44.0 2 | // Stolen somewhat and adapted to Flow from https://github.com/DefinitelyTyped/DefinitelyTyped 3 | 4 | type ButtonEnum = { 5 | LEFT: number, 6 | MIDDLE: number, 7 | RIGHT: number 8 | }; 9 | 10 | type KeyEnum = { 11 | NULL: string, 12 | CANCEL: string, // ^break 13 | HELP: string, 14 | BACK_SPACE: string, 15 | TAB: string, 16 | CLEAR: string, 17 | RETURN: string, 18 | ENTER: string, 19 | SHIFT: string, 20 | CONTROL: string, 21 | ALT: string, 22 | PAUSE: string, 23 | ESCAPE: string, 24 | SPACE: string, 25 | PAGE_UP: string, 26 | PAGE_DOWN: string, 27 | END: string, 28 | HOME: string, 29 | ARROW_LEFT: string, 30 | LEFT: string, 31 | ARROW_UP: string, 32 | UP: string, 33 | ARROW_RIGHT: string, 34 | RIGHT: string, 35 | ARROW_DOWN: string, 36 | DOWN: string, 37 | INSERT: string, 38 | DELETE: string, 39 | SEMICOLON: string, 40 | EQUALS: string, 41 | NUMPAD0: string, // number pad keys 42 | NUMPAD1: string, 43 | NUMPAD2: string, 44 | NUMPAD3: string, 45 | NUMPAD4: string, 46 | NUMPAD5: string, 47 | NUMPAD6: string, 48 | NUMPAD7: string, 49 | NUMPAD8: string, 50 | NUMPAD9: string, 51 | MULTIPLY: string, 52 | ADD: string, 53 | SEPARATOR: string, 54 | SUBTRACT: string, 55 | DECIMAL: string, 56 | DIVIDE: string, 57 | F1: string, // function keys 58 | F2: string, 59 | F3: string, 60 | F4: string, 61 | F5: string, 62 | F6: string, 63 | F7: string, 64 | F8: string, 65 | F9: string, 66 | F10: string, 67 | F11: string, 68 | F12: string, 69 | COMMAND: string, // Apple command key 70 | META: string, // alias for Windows key 71 | chord: (...var_args: Array) => string 72 | }; 73 | 74 | type BrowserEnum = { 75 | ANDROID: string, 76 | CHROME: string, 77 | FIREFOX: string, 78 | INTERNET_EXPLORER: string, 79 | IPAD: string, 80 | IPHONE: string, 81 | OPERA: string, 82 | PHANTOM_JS: string, 83 | SAFARI: string, 84 | HTMLUNIT: string 85 | }; 86 | 87 | type CapabilityEnum = { 88 | ACCEPT_SSL_CERTS: string, 89 | BROWSER_NAME: string, 90 | ELEMENT_SCROLL_BEHAVIOR: string, 91 | HANDLES_ALERTS: string, 92 | LOGGING_PREFS: string, 93 | NATIVE_EVENTS: string, 94 | PLATFORM: string, 95 | PROXY: string, 96 | ROTATABLE: string, 97 | SECURE_SSL: string, 98 | SUPPORTS_APPLICATION_CACHE: string, 99 | SUPPORTS_CSS_SELECTORS: string, 100 | SUPPORTS_JAVASCRIPT: string, 101 | SUPPORTS_LOCATION_CONTEXT: string, 102 | TAKES_SCREENSHOT: string, 103 | UNEXPECTED_ALERT_BEHAVIOR: string, 104 | VERSION: string 105 | } 106 | 107 | type CommandNameEnum = { 108 | GET_SERVER_STATUS: string, 109 | NEW_SESSION: string, 110 | GET_SESSIONS: string, 111 | DESCRIBE_SESSION: string, 112 | CLOSE: string, 113 | QUIT: string, 114 | GET_CURRENT_URL: string, 115 | GET: string, 116 | GO_BACK: string, 117 | GO_FORWARD: string, 118 | REFRESH: string, 119 | ADD_COOKIE: string, 120 | GET_COOKIE: string, 121 | GET_ALL_COOKIES: string, 122 | DELETE_COOKIE: string, 123 | DELETE_ALL_COOKIES: string, 124 | GET_ACTIVE_ELEMENT: string, 125 | FIND_ELEMENT: string, 126 | FIND_ELEMENTS: string, 127 | FIND_CHILD_ELEMENT: string, 128 | FIND_CHILD_ELEMENTS: string, 129 | CLEAR_ELEMENT: string, 130 | CLICK_ELEMENT: string, 131 | SEND_KEYS_TO_ELEMENT: string, 132 | SUBMIT_ELEMENT: string, 133 | GET_CURRENT_WINDOW_HANDLE: string, 134 | GET_WINDOW_HANDLES: string, 135 | GET_WINDOW_POSITION: string, 136 | SET_WINDOW_POSITION: string, 137 | GET_WINDOW_SIZE: string, 138 | SET_WINDOW_SIZE: string, 139 | MAXIMIZE_WINDOW: string, 140 | SWITCH_TO_WINDOW: string, 141 | SWITCH_TO_FRAME: string, 142 | GET_PAGE_SOURCE: string, 143 | GET_TITLE: string, 144 | EXECUTE_SCRIPT: string, 145 | EXECUTE_ASYNC_SCRIPT: string, 146 | GET_ELEMENT_TEXT: string, 147 | GET_ELEMENT_TAG_NAME: string, 148 | IS_ELEMENT_SELECTED: string, 149 | IS_ELEMENT_ENABLED: string, 150 | IS_ELEMENT_DISPLAYED: string, 151 | GET_ELEMENT_LOCATION: string, 152 | GET_ELEMENT_LOCATION_IN_VIEW: string, 153 | GET_ELEMENT_SIZE: string, 154 | GET_ELEMENT_ATTRIBUTE: string, 155 | GET_ELEMENT_VALUE_OF_CSS_PROPERTY: string, 156 | ELEMENT_EQUALS: string, 157 | SCREENSHOT: string, 158 | IMPLICITLY_WAIT: string, 159 | SET_SCRIPT_TIMEOUT: string, 160 | SET_TIMEOUT: string, 161 | ACCEPT_ALERT: string, 162 | DISMISS_ALERT: string, 163 | GET_ALERT_TEXT: string, 164 | SET_ALERT_TEXT: string, 165 | EXECUTE_SQL: string, 166 | GET_LOCATION: string, 167 | SET_LOCATION: string, 168 | GET_APP_CACHE: string, 169 | GET_APP_CACHE_STATUS: string, 170 | CLEAR_APP_CACHE: string, 171 | IS_BROWSER_ONLINE: string, 172 | SET_BROWSER_ONLINE: string, 173 | GET_LOCAL_STORAGE_ITEM: string, 174 | GET_LOCAL_STORAGE_KEYS: string, 175 | SET_LOCAL_STORAGE_ITEM: string, 176 | REMOVE_LOCAL_STORAGE_ITEM: string, 177 | CLEAR_LOCAL_STORAGE: string, 178 | GET_LOCAL_STORAGE_SIZE: string, 179 | GET_SESSION_STORAGE_ITEM: string, 180 | GET_SESSION_STORAGE_KEYS: string, 181 | SET_SESSION_STORAGE_ITEM: string, 182 | REMOVE_SESSION_STORAGE_ITEM: string, 183 | CLEAR_SESSION_STORAGE: string, 184 | GET_SESSION_STORAGE_SIZE: string, 185 | SET_SCREEN_ORIENTATION: string, 186 | GET_SCREEN_ORIENTATION: string, 187 | CLICK: string, 188 | DOUBLE_CLICK: string, 189 | MOUSE_DOWN: string, 190 | MOUSE_UP: string, 191 | MOVE_TO: string, 192 | SEND_KEYS_TO_ACTIVE_ELEMENT: string, 193 | TOUCH_SINGLE_TAP: string, 194 | TOUCH_DOWN: string, 195 | TOUCH_UP: string, 196 | TOUCH_MOVE: string, 197 | TOUCH_SCROLL: string, 198 | TOUCH_DOUBLE_TAP: string, 199 | TOUCH_LONG_PRESS: string, 200 | TOUCH_FLICK: string, 201 | GET_AVAILABLE_LOG_TYPES: string, 202 | GET_LOG: string, 203 | GET_SESSION_LOGS: string 204 | } 205 | 206 | declare type WebDriverByLib = { 207 | className(value: string): WebDriverLocator; 208 | css(value: string): WebDriverLocator; 209 | id(value: string): WebDriverLocator; 210 | linkText(value: string): WebDriverLocator; 211 | js(script: any, ...var_args: any[]): (WebDriver: WebDriverClass) => WebDriverPromise; 212 | name(value: string): WebDriverLocator; 213 | partialLinkText(value: string): WebDriverLocator; 214 | tagName(value: string): WebDriverLocator; 215 | xpath(value: string): WebDriverLocator; 216 | }; 217 | 218 | declare type ByHash = {className: string} | 219 | {css: string} | 220 | {id: string} | 221 | {js: string} | 222 | {linkText: string} | 223 | {name: string} | 224 | {partialLinkText: string} | 225 | {tagName: string} | 226 | {xpath: string}; 227 | 228 | declare type ErrorCodeEnum = { 229 | SUCCESS: number, 230 | NO_SUCH_ELEMENT: number, 231 | NO_SUCH_FRAME: number, 232 | UNKNOWN_COMMAND: number, 233 | UNSUPPORTED_OPERATION: number, // Alias for UNKNOWN_COMMAND. 234 | STALE_ELEMENT_REFERENCE: number, 235 | ELEMENT_NOT_VISIBLE: number, 236 | INVALID_ELEMENT_STATE: number, 237 | UNKNOWN_ERROR: number, 238 | ELEMENT_NOT_SELECTABLE: number, 239 | JAVASCRIPT_ERROR: number, 240 | XPATH_LOOKUP_ERROR: number, 241 | TIMEOUT: number, 242 | NO_SUCH_WINDOW: number, 243 | INVALID_COOKIE_DOMAIN: number, 244 | UNABLE_TO_SET_COOKIE: number, 245 | MODAL_DIALOG_OPENED: number, 246 | UNEXPECTED_ALERT_OPEN: number, 247 | NO_SUCH_ALERT: number, 248 | NO_MODAL_DIALOG_OPEN: number, 249 | SCRIPT_TIMEOUT: number, 250 | INVALID_ELEMENT_COORDINATES: number, 251 | IME_NOT_AVAILABLE: number, 252 | IME_ENGINE_ACTIVATION_FAILED: number, 253 | INVALID_SELECTOR_ERROR: number, 254 | SESSION_NOT_CREATED: number, 255 | MOVE_TARGET_OUT_OF_BOUNDS: number, 256 | SQL_DATABASE_ERROR: number, 257 | INVALID_XPATH_SELECTOR: number, 258 | INVALID_XPATH_SELECTOR_RETURN_TYPE: number, 259 | METHOD_NOT_ALLOWED: number; 260 | } 261 | 262 | declare class WebDriverError extends Error { 263 | constructor(code: number, opt_message?: string): WebDriverError; 264 | code: number; 265 | State: { 266 | ELEMENT_NOT_SELECTABLE: string; 267 | ELEMENT_NOT_VISIBLE: string; 268 | IME_ENGINE_ACTIVATION_FAILED: string; 269 | IME_NOT_AVAILABLE: string; 270 | INVALID_COOKIE_DOMAIN: string; 271 | INVALID_ELEMENT_COORDINATES: string; 272 | INVALID_ELEMENT_STATE: string; 273 | INVALID_SELECTOR: string; 274 | JAVASCRIPT_ERROR: string; 275 | MOVE_TARGET_OUT_OF_BOUNDS: string; 276 | NO_SUCH_ALERT: string; 277 | NO_SUCH_DOM: string; 278 | NO_SUCH_ELEMENT: string; 279 | NO_SUCH_FRAME: string; 280 | NO_SUCH_WINDOW: string; 281 | SCRIPT_TIMEOUT: string; 282 | SESSION_NOT_CREATED: string; 283 | STALE_ELEMENT_REFERENCE: string; 284 | SUCCESS: string; 285 | TIMEOUT: string; 286 | UNABLE_TO_SET_COOKIE: string; 287 | UNEXPECTED_ALERT_OPEN: string; 288 | UNKNOWN_COMMAND: string; 289 | UNKNOWN_ERROR: string; 290 | UNSUPPORTED_OPERATION: string; 291 | }; 292 | state: string; 293 | message: string; 294 | name: string; 295 | stack: string; 296 | isAutomationError: boolean; 297 | toString(): string; 298 | } 299 | 300 | declare type WebDriverErrorLib = { 301 | ErrorCode: ErrorCodeEnum, 302 | WebDriverError: WebDriverError 303 | }; 304 | 305 | // ///////////////// 306 | 307 | declare class WebDriverLoggingPreferences { 308 | setLevel(type: string, level: { value: number, name: string }): void; 309 | toJSON(): { [key: string]: string }; 310 | } 311 | 312 | declare type TypeEnum = { 313 | BROWSER: string, 314 | CLIENT: string, 315 | DRIVER: string, 316 | PERFORMANCE: string, 317 | SERVER: string 318 | }; 319 | 320 | declare type LevelEnum = { 321 | ALL: { value: number, name: string }, 322 | DEBUG: { value: number, name: string }, 323 | INFO: { value: number, name: string }, 324 | WARNING: { value: number, name: string }, 325 | SEVERE: { value: number, name: string }, 326 | OFF: { value: number, name: string } 327 | }; 328 | 329 | declare class WebDriverEntry { 330 | constructor(level: { value: number, name: string } | string, message: string, opt_timestamp?: number, opt_type?: string): WebDriverEntry; 331 | level: { value: number, name: string }; 332 | message: string; 333 | timestamp: number; 334 | type: string; 335 | static fromClosureLogRecord(logRecord: any, opt_type?: string): WebDriverEntry; 336 | toJSON(): { 337 | level: string, 338 | message: string, 339 | timestamp: number, 340 | type: string 341 | } 342 | } 343 | 344 | declare type WebDriverLoggingLib = { 345 | Preferences: WebDriverLoggingPreferences, 346 | Type: TypeEnum, 347 | Level: LevelEnum, 348 | getLevel(nameOrValue: string): { value: number, name: string }, 349 | getLevel(nameOrValue: number): { value: number, name: string }, 350 | Entry: WebDriverEntry 351 | }; 352 | 353 | // ///////////////// 354 | 355 | declare class WebDriverCancellationError { 356 | name: string; 357 | message: string 358 | } 359 | 360 | declare class WebDriverPromise extends Promise { 361 | constructor(resolver: (onFulfilled: (value: T | WebDriverPromise | WebDriverThenable | void)=> void, onRejected: (reason: any)=> void)=>void, opt_flow?: WebDriverControlFlow): WebDriverPromise<*>; 362 | constructor(opt_msg?: string): WebDriverPromise; 363 | cancel(opt_reason?: string): void; 364 | isPending(): boolean; 365 | then(opt_callback?: (value: T) => WebDriverPromise | Promise | R, opt_errback?: (error: any) => any): WebDriverPromise; 366 | thenCatch(errback: (error: any) => any): WebDriverPromise; 367 | thenFinally(callback: () => any): WebDriverPromise; 368 | } 369 | 370 | declare class WebDriverThenable extends WebDriverPromise { 371 | static addImplementation(ctor: Function): void; 372 | static isImplementation(object: any): boolean; 373 | } 374 | 375 | declare class WebDriverDeferred extends WebDriverPromise { 376 | constructor(opt_flow?: WebDriverControlFlow): WebDriverDeferred<*>; 377 | static State_: { 378 | BLOCKED: number, 379 | PENDING: number, 380 | REJECTED: number, 381 | RESOLVED: number 382 | }; 383 | promise: WebDriverPromise; 384 | reject(opt_error?: any): void; 385 | errback(opt_error?: any): void; 386 | fulfill(opt_value?: T): void; 387 | removeAll(): void; 388 | } 389 | 390 | declare class WebDriverControlFlow extends WebDriverEventEmitter { 391 | constructor(): WebDriverControlFlow; 392 | static EventType: { 393 | IDLE: string; 394 | RESET: string; 395 | SCHEDULE_TASK: string; 396 | UNCAUGHT_EXCEPTION: string; 397 | }; 398 | toString(): string; 399 | reset(): void; 400 | getSchedule(opt_includeStackTraces?: boolean): string; 401 | execute(fn: ()=>(T | WebDriverPromise) | Generator, opt_description?: string): WebDriverPromise; 402 | timeout(ms: number, opt_description?: string): WebDriverPromise; 403 | wait(condition: WebDriverPromise | Function, opt_timeout?: number, opt_message?: string): WebDriverPromise; 404 | } 405 | 406 | declare type WebDriverPromiseLib = { 407 | all(arr: WebDriverPromise[]): WebDriverPromise, 408 | asap(value: any, callback: Function, opt_errback?: Function): void, 409 | controlFlow(): WebDriverControlFlow, 410 | createFlow(callback: (flow: WebDriverControlFlow) => R): WebDriverPromise, 411 | isPromise(value: any): boolean, 412 | isGenerator(fn: Function): boolean, 413 | delayed(ms: number): WebDriverPromise, 414 | filter(arr: T[], fn: (element: T, index: number, array: T[]) => any, opt_self?: any): WebDriverPromise, 415 | filter(arr: WebDriverPromise, fn: (element: T, index: number, array: T[]) => any, opt_self?: any): WebDriverPromise, 416 | defer(): WebDriverDeferred, 417 | fulfilled(opt_value?: T): WebDriverPromise, 418 | map(arr: T[] | WebDriverPromise, fn: (element: T, index: number, array: T[]) => any, opt_self?: any): WebDriverPromise, 419 | rejected(opt_reason?: any): WebDriverPromise, 420 | checkedNodeCall(fn: Function, ...var_args: any[]): WebDriverPromise, 421 | consume(generatorFn: Function, opt_self?: any, ...var_args: any[]): WebDriverPromise, 422 | when(value: T, opt_callback?: (value: T) => any, opt_errback?: (error: any) => any): WebDriverPromise, 423 | when(value: WebDriverPromise, opt_callback?: (value: T) => any, opt_errback?: (error: any) => any): WebDriverPromise, 424 | fullyResolved(value: any): WebDriverPromise, 425 | setDefaultFlow(flow: WebDriverControlFlow): void, 426 | CancellationError: WebDriverCancellationError, 427 | Thenable: WebDriverThenable<*>, 428 | Promise: WebDriverPromise<*>, 429 | Deferred: WebDriverDeferred<*>, 430 | ControlFlow: WebDriverControlFlow 431 | } 432 | 433 | // ///////////// 434 | 435 | declare class WebDriverFrame { 436 | constructor(context?: string, name?: string, alias?: string, path?: string): WebDriverFrame; 437 | getName(): string; 438 | getUrl(): string; 439 | getLine(): number; 440 | getColumn(): number; 441 | isAnonymous(): boolean; 442 | toString(): string; 443 | } 444 | 445 | declare class WebDriverSnapshot { 446 | constructor(opt_slice?: number): WebDriverSnapshot; 447 | getStacktrace(): WebDriverFrame[]; 448 | } 449 | 450 | declare type WebDriverStacktraceLib = { 451 | Frame: WebDriverFrame, 452 | Snapshot: WebDriverSnapshot, 453 | format(error: any): any, 454 | get(): WebDriverFrame[], 455 | BROWSER_SUPPORTED: boolean 456 | } 457 | 458 | // ////////// 459 | 460 | declare class WebDriverCondition { 461 | constructor(message: string, fn: (webdriver: WebDriverClass) => any): WebDriverCondition; 462 | description(): string; 463 | fn(webdriver: WebDriverClass): any; 464 | } 465 | 466 | declare type WebDriverUntilLib = { 467 | Condition: WebDriverCondition<*>, 468 | ableToSwitchToFrame(frame: number | WebDriverElement | WebDriverLocator | ByHash | ((webdriver: WebDriverClass)=>WebDriverElement)): WebDriverCondition; 469 | alertIsPresent(): WebDriverCondition; 470 | elementIsDisabled(element: WebDriverElement): WebDriverCondition; 471 | elementIsEnabled(element: WebDriverElement): WebDriverCondition; 472 | elementIsNotSelected(element: WebDriverElement): WebDriverCondition; 473 | elementIsNotVisible(element: WebDriverElement): WebDriverCondition; 474 | elementIsSelected(element: WebDriverElement): WebDriverCondition; 475 | elementIsVisible(element: WebDriverElement): WebDriverCondition; 476 | elementLocated(locator: WebDriverLocator | ByHash | Function): WebDriverCondition; 477 | elementTextContains(element: WebDriverElement, substr: string): WebDriverCondition; 478 | elementTextIs(element: WebDriverElement, text: string): WebDriverCondition; 479 | elementTextMatches(element: WebDriverElement, regex: RegExp): WebDriverCondition; 480 | elementsLocated(locator: WebDriverLocator | ByHash | Function): WebDriverCondition; 481 | stalenessOf(element: WebDriverElement): WebDriverCondition; 482 | titleContains(substr: string): WebDriverCondition; 483 | titleIs(title: string): WebDriverCondition; 484 | titleMatches(regex: RegExp): WebDriverCondition; 485 | } 486 | 487 | // /////////// 488 | // CLASSES 489 | 490 | declare type location = { 491 | x: number, 492 | y: number 493 | }; 494 | declare type offset = { 495 | x: number, 496 | y: number 497 | }; 498 | declare type speed = { 499 | xspeed: number, 500 | yspeed: number 501 | } 502 | 503 | declare type size = { 504 | width: number, 505 | height: number 506 | } 507 | 508 | declare class WebDriverActionSequence { 509 | perform(): WebDriverPromise; 510 | mouseMove(location: WebDriverElement, opt_offset?: location): WebDriverActionSequence; 511 | mouseMove(location: location): WebDriverActionSequence; 512 | mouseDown(opt_elementOrButton?: WebDriverElement, opt_button?: number): WebDriverActionSequence; 513 | mouseDown(opt_elementOrButton?: number): WebDriverActionSequence; 514 | mouseUp(opt_elementOrButton?: WebDriverElement, opt_button?: number): WebDriverActionSequence; 515 | mouseUp(opt_elementOrButton?: number): WebDriverActionSequence; 516 | dragAndDrop(element: WebDriverElement, location: WebDriverElement): WebDriverActionSequence; 517 | dragAndDrop(element: WebDriverElement, location: location): WebDriverActionSequence; 518 | click(opt_elementOrButton?: WebDriverElement, opt_button?: number): WebDriverActionSequence; 519 | click(opt_elementOrButton?: number): WebDriverActionSequence; 520 | doubleClick(opt_elementOrButton?: WebDriverElement, opt_button?: number): WebDriverActionSequence; 521 | doubleClick(opt_elementOrButton?: number): WebDriverActionSequence; 522 | keyDown(key: string): WebDriverActionSequence; 523 | keyUp(key: string): WebDriverActionSequence; 524 | sendKeys(...var_args: any[]): WebDriverActionSequence; 525 | } 526 | 527 | declare class WebDriverTouchSequence { 528 | constructor(driver: WebDriverClass): WebDriverTouchSequence; 529 | perform(): WebDriverPromise; 530 | tap(elem: WebDriverElement): WebDriverTouchSequence; 531 | doubleTap(elem: WebDriverElement): WebDriverTouchSequence; 532 | longPress(elem: WebDriverElement): WebDriverTouchSequence; 533 | tapAndHold(location: location): WebDriverTouchSequence; 534 | move(location: location): WebDriverTouchSequence; 535 | release(location: location): WebDriverTouchSequence; 536 | scroll(offset: offset): WebDriverTouchSequence; 537 | scrollFromElement(elem: WebDriverElement, offset: offset): WebDriverTouchSequence; 538 | flick(speed: speed): WebDriverTouchSequence; 539 | flickElement(elem: WebDriverElement, offset: offset, speed: number): WebDriverTouchSequence; 540 | } 541 | 542 | declare class WebDriverAlert { 543 | getText(): WebDriverPromise; 544 | accept(): WebDriverPromise; 545 | dismiss(): WebDriverPromise; 546 | sendKeys(text: string): WebDriverPromise; 547 | } 548 | 549 | declare class WebDriverAlertPromise extends WebDriverAlert { 550 | cancel(opt_reason?: string): void; 551 | isPending(): boolean; 552 | then(opt_callback?: (value: WebDriverAlert) => WebDriverPromise, opt_errback?: (error: any) => any): WebDriverPromise; 553 | then(opt_callback?: (value: WebDriverAlert) => R, opt_errback?: (error: any) => any): WebDriverPromise; 554 | thenCatch(errback: (error: any) => any): WebDriverPromise; 555 | thenFinally(callback: () => any): WebDriverPromise; 556 | } 557 | 558 | declare type proxyConfig = { 559 | proxyType: string, 560 | proxyAutoconfigUrl?: string, 561 | ftpProxy?: string, 562 | httpProxy?: string, 563 | sslProxy?: string, 564 | noProxy?: string 565 | } 566 | 567 | declare class WebDriverBuilder { 568 | constructor(): void; 569 | forBrowser(name: string, opt_version?: string, opt_platform?: string): WebDriverBuilder; 570 | build(): WebDriverClass; 571 | buildAsync(): WebDriverPromise; 572 | getCapabilities(): WebDriverCapabilities; 573 | getServerUrl(): string; 574 | setAlertBehavior(behavior: string): WebDriverBuilder; 575 | // setChromeOptions(options: chrome.Options): WebDriverBuilder; 576 | setControlFlow(flow: WebDriverControlFlow): WebDriverBuilder; 577 | setEnableNativeEvents(enabled: boolean): WebDriverBuilder; 578 | // setFirefoxOptions(options: firefox.Options): WebDriverBuilder; 579 | setLoggingPrefs(prefs: WebDriverLoggingPreferences): WebDriverBuilder; 580 | setLoggingPrefs(prefs: { [key: string]: string }): WebDriverBuilder; 581 | setProxy(config: proxyConfig): WebDriverBuilder; 582 | setScrollBehavior(behavior: number): WebDriverBuilder; 583 | usingServer(url: string): WebDriverBuilder; 584 | withCapabilities(capabilities: WebDriverCapabilities): WebDriverBuilder; 585 | withCapabilities(capabilities: any): WebDriverBuilder; 586 | } 587 | 588 | declare class WebDriverCapabilities { 589 | constructor(opt_other?: any): WebDriverCapabilities; 590 | toJSON(): any; 591 | merge(other: WebDriverCapabilities): WebDriverCapabilities; 592 | merge(other: any): WebDriverCapabilities; 593 | set(key: string, value: any): WebDriverCapabilities; 594 | setLoggingPrefs(prefs: WebDriverLoggingPreferences): WebDriverCapabilities; 595 | setLoggingPrefs(prefs: { [key: string]: string }): WebDriverCapabilities; 596 | setProxy(proxy: proxyConfig): WebDriverCapabilities; 597 | setEnableNativeEvents(enabled: boolean): WebDriverCapabilities; 598 | setScrollBehavior(behavior: number): WebDriverCapabilities; 599 | setAlertBehavior(behavior: string): WebDriverCapabilities; 600 | get(key: string): any; 601 | has(key: string): boolean; 602 | static android(): WebDriverCapabilities; 603 | static chrome(): WebDriverCapabilities; 604 | static firefox(): WebDriverCapabilities; 605 | static ie(): WebDriverCapabilities; 606 | static ipad(): WebDriverCapabilities; 607 | static iphone(): WebDriverCapabilities; 608 | static opera(): WebDriverCapabilities; 609 | static phantomjs(): WebDriverCapabilities; 610 | static safari(): WebDriverCapabilities; 611 | static htmlunit(): WebDriverCapabilities; 612 | static htmlunitwithjs(): WebDriverCapabilities; 613 | } 614 | 615 | declare class WebDriverCommand { 616 | constructor(name: string): WebDriverCommand; 617 | getName(): string; 618 | setParameter(name: string, value: any): WebDriverCommand; 619 | setParameters(parameters: any): WebDriverCommand; 620 | getParameter(key: string): any; 621 | getParameters(): any; 622 | } 623 | 624 | declare class WebDriverEventEmitter { 625 | constructor(): WebDriverEventEmitter; 626 | emit(type: string, ...var_args: any[]): void; 627 | listeners(type: string): Array<{fn: Function; oneshot: boolean; scope: any;}>; 628 | addListener(type: string, listenerFn: Function, opt_scope?: any): WebDriverEventEmitter; 629 | once(type: string, listenerFn: any, opt_scope?: any): WebDriverEventEmitter; 630 | on(type: string, listenerFn: Function, opt_scope?: any): WebDriverEventEmitter; 631 | removeListener(type: string, listenerFn: Function): WebDriverEventEmitter; 632 | removeAllListeners(opt_type?: string): WebDriverEventEmitter; 633 | } 634 | 635 | declare class WebDriverFileDetector { 636 | constructor(): WebDriverFileDetector; 637 | handleFile(driver: WebDriverClass, path: string): WebDriverPromise; 638 | } 639 | 640 | // WebDriver sub classes 641 | 642 | declare class WebDriverNavigation { 643 | to(url: string): WebDriverPromise; 644 | back(): WebDriverPromise; 645 | forward(): WebDriverPromise; 646 | refresh(): WebDriverPromise; 647 | } 648 | 649 | declare type optionsCookie = { 650 | name: string, 651 | value: string, 652 | path?: string, 653 | domain?: string, 654 | secure?: boolean, 655 | expiry?: number 656 | } 657 | 658 | declare class WebDriverOptions { 659 | addCookie(name: string, value: string, opt_path?: string, opt_domain?: string, opt_isSecure?: boolean, opt_expiry?: number): WebDriverPromise; 660 | addCookie(name: string, value: string, opt_path?: string, opt_domain?: string, opt_isSecure?: boolean, opt_expiry?: Date): WebDriverPromise; 661 | deleteAllCookies(): WebDriverPromise; 662 | deleteCookie(name: string): WebDriverPromise; 663 | getCookies(): WebDriverPromise; 664 | getCookie(name: string): WebDriverPromise; 665 | logs(): WebDriverLogs; 666 | timeouts(): WebDriverTimeouts; 667 | window(): WebDriverWindow; 668 | } 669 | 670 | declare class WebDriverTimeouts { 671 | implicitlyWait(ms: number): WebDriverPromise; 672 | setScriptTimeout(ms: number): WebDriverPromise; 673 | pageLoadTimeout(ms: number): WebDriverPromise; 674 | } 675 | 676 | declare class WebDriverWindow { 677 | getPosition(): WebDriverPromise; 678 | setPosition(x: number, y: number): WebDriverPromise; 679 | getSize(): WebDriverPromise; 680 | setSize(width: number, height: number): WebDriverPromise; 681 | maximize(): WebDriverPromise; 682 | } 683 | 684 | declare class WebDriverLogs { 685 | get(type: string): WebDriverPromise; 686 | getAvailableLogTypes(): WebDriverPromise; 687 | } 688 | 689 | declare class WebDriverTargetLocator { 690 | activeElement(): WebDriverElementPromise; 691 | defaultContent(): WebDriverPromise; 692 | frame(nameOrIndex: string): WebDriverPromise; 693 | frame(nameOrIndex: number): WebDriverPromise; 694 | window(nameOrHandle: string): WebDriverPromise; 695 | alert(): WebDriverAlertPromise; 696 | } 697 | 698 | declare class WebDriverCommandExecutor { 699 | execute(command: WebDriverCommand, callback: (error: WebDriverError, responseObject: any) => any): void; 700 | } 701 | 702 | declare class WebDriverClass { 703 | constructor(session: WebDriverSession | WebDriverPromise, executor: WebDriverCommandExecutor, opt_flow?: WebDriverControlFlow): WebDriverClass; 704 | static Navigation: WebDriverNavigation; 705 | static Options: WebDriverOptions; 706 | static Timeouts: WebDriverTimeouts; 707 | static Window: WebDriverWindow; 708 | static Logs: WebDriverLogs; 709 | static TargetLocator: WebDriverTargetLocator; 710 | static attachToSession(executor: WebDriverCommandExecutor, sessionId: string, opt_flow?: WebDriverControlFlow): WebDriverClass; 711 | static createSession(executor: WebDriverCommandExecutor, desiredCapabilities: WebDriverCapabilities, opt_flow?: WebDriverControlFlow): WebDriverClass; 712 | controlFlow(): WebDriverControlFlow; 713 | schedule(command: WebDriverCommand, description: string): WebDriverPromise; 714 | setFileDetector(detector: WebDriverFileDetector): void; 715 | getSession(): WebDriverPromise; 716 | getCapabilities(): WebDriverPromise; 717 | quit(): WebDriverPromise; 718 | actions(): WebDriverActionSequence; 719 | touchActions(): WebDriverTouchSequence; 720 | executeScript(script: string, ...var_args: any[]): WebDriverPromise; 721 | executeScript(script: Function, ...var_args: any[]): WebDriverPromise; 722 | executeAsyncScript(script: string | Function, ...var_args: any[]): WebDriverPromise; 723 | call(fn: (...var_args: any[])=>(T | WebDriverPromise), opt_scope?: any, ...var_args: any[]): WebDriverPromise; 724 | wait(condition: WebDriverPromise | WebDriverCondition | ((driver: WebDriverClass)=>T), timeout?: number, opt_message?: string): WebDriverPromise; 725 | sleep(ms: number): WebDriverPromise; 726 | getWindowHandle(): WebDriverPromise; 727 | getAllWindowHandles(): WebDriverPromise; 728 | getPageSource(): WebDriverPromise; 729 | close(): WebDriverPromise; 730 | get(url: string): WebDriverPromise; 731 | getCurrentUrl(): WebDriverPromise; 732 | getTitle(): WebDriverPromise; 733 | findElement(locatorOrElement: WebDriverLocator | WebDriverElement | ByHash | Function): WebDriverElementPromise; 734 | isElementPresent(locatorOrElement: WebDriverLocator | ByHash | WebDriverElement | Function): WebDriverPromise; 735 | findElements(locator: WebDriverLocator | ByHash | Function): WebDriverPromise; 736 | takeScreenshot(): WebDriverPromise; 737 | manage(): WebDriverOptions; 738 | navigate(): WebDriverNavigation; 739 | switchTo(): WebDriverTargetLocator; 740 | } 741 | 742 | declare class WebDriverElement { 743 | constructor(driver: WebDriverClass, id: WebDriverPromise<{ELEMENT: string}> | {ELEMENT: string}): WebDriverElement; 744 | serialize(): {ELEMENT: string} | WebDriverPromise<{ELEMENT: string}>; 745 | static Id: {ELEMENT: string}; 746 | static ELEMENT_KEY: string; 747 | getDriver(): WebDriverClass; 748 | findElement(locator: WebDriverLocator | ByHash | Function): WebDriverElementPromise; 749 | isElementPresent(locator: WebDriverLocator | ByHash | Function): WebDriverPromise; 750 | findElements(locator: WebDriverLocator | ByHash | Function): WebDriverPromise; 751 | click(): WebDriverPromise; 752 | sendKeys(...var_args: Array>): WebDriverPromise; 753 | getTagName(): WebDriverPromise; 754 | getCssValue(cssStyleProperty: string): WebDriverPromise; 755 | getAttribute(attributeName: string): WebDriverPromise; 756 | getText(): WebDriverPromise; 757 | getSize(): WebDriverPromise; 758 | getLocation(): WebDriverPromise; 759 | isEnabled(): WebDriverPromise; 760 | isSelected(): WebDriverPromise; 761 | submit(): WebDriverPromise; 762 | clear(): WebDriverPromise; 763 | isDisplayed(): WebDriverPromise; 764 | getOuterHtml(): WebDriverPromise; 765 | getId(): WebDriverPromise<{ELEMENT: string}>; 766 | getRawId(): WebDriverPromise; 767 | getInnerHtml(): WebDriverPromise; 768 | static equals(a: WebDriverElement, b: WebDriverElement): WebDriverPromise; 769 | } 770 | 771 | declare class WebDriverElementPromise extends WebDriverElement { 772 | cancel(opt_reason?: string): void; 773 | isPending(): boolean; 774 | then(opt_callback?: (value: WebDriverElement) => WebDriverPromise, opt_errback?: (error: any) => any): WebDriverPromise; 775 | then(opt_callback?: (value: WebDriverElement) => R, opt_errback?: (error: any) => any): WebDriverPromise; 776 | thenCatch(errback: (error: any) => any): WebDriverPromise; 777 | thenFinally(callback: () => any): WebDriverPromise; 778 | } 779 | 780 | declare class WebDriverLocator { 781 | constructor(using: string, value: string): WebDriverLocator; 782 | static checkLocator(value: any): WebDriverLocator | Function; 783 | using: string; 784 | value: string; 785 | toString(): string; 786 | } 787 | 788 | declare class WebDriverSession { 789 | constructor(id: string, capabilities: any): WebDriverSession; 790 | getId(): string; 791 | getCapabilities(): WebDriverCapabilities; 792 | getCapability(key: string): any; 793 | toJSON(): string; 794 | } 795 | 796 | declare module 'selenium-webdriver' { 797 | // libs 798 | declare var By: WebDriverByLib; 799 | declare var error: WebDriverErrorLib; 800 | declare var logging: WebDriverLoggingLib; 801 | declare var promise: WebDriverPromiseLib; 802 | declare var stacktrace: WebDriverStacktraceLib; 803 | declare var until: WebDriverUntilLib; 804 | 805 | // classes 806 | declare var ActionSequence: typeof WebDriverActionSequence; 807 | declare var TouchSequence: typeof WebDriverTouchSequence; 808 | declare var Builder: typeof WebDriverBuilder; 809 | declare var Capabilities: typeof WebDriverCapabilities; 810 | declare var Command: typeof WebDriverCommand; 811 | declare var EventEmitter: typeof WebDriverEventEmitter; 812 | declare var FileDetector: typeof WebDriverFileDetector; 813 | declare var WebDriver: typeof WebDriverClass; 814 | declare var WebElement: typeof WebDriverElement; 815 | declare var WebElementPromise: typeof WebDriverElementPromise; 816 | declare var Locator: typeof WebDriverLocator; 817 | declare var Session: typeof WebDriverSession; 818 | 819 | // props 820 | declare var Button: ButtonEnum; 821 | declare var Key: KeyEnum; 822 | declare var Browser: BrowserEnum; 823 | declare var Capability: CapabilityEnum; 824 | declare var CommandName: CommandNameEnum; 825 | } 826 | 827 | // /// TESTING 828 | 829 | declare module 'selenium-webdriver/testing' { 830 | declare type WebDriverTest = { 831 | describe(name: string, fn: Function): void; 832 | xdescribe(name: string, fn: Function): void; 833 | after(fn: Function): void; 834 | afterEach(fn: Function): void; 835 | before(fn: Function): void; 836 | beforeEach(fn: Function): void; 837 | it(name: string, fn: Function): void; 838 | iit(name: string, fn: Function): void; 839 | xit(name: string, fn: Function): void; 840 | } 841 | declare var exports: WebDriverTest 842 | } 843 | 844 | // /// CHROME 845 | 846 | declare type optionsValues = { 847 | args: string[], 848 | binary?: string, 849 | detach: boolean, 850 | extensions: string[], 851 | localState?: any, 852 | logFile?: string, 853 | prefs?: any 854 | }; 855 | 856 | declare type perfLoggingPrefs = { 857 | enableNetwork: boolean, 858 | enablePage: boolean, 859 | enableTimeline: boolean, 860 | tracingCategories: string, 861 | bufferUsageReportingInterval: number 862 | }; 863 | 864 | declare class ChromeOptions { 865 | constructor(): ChromeOptions; 866 | static fromCapabilities(capabilities: WebDriverCapabilities): ChromeOptions; 867 | addArguments(...var_args: string[]): ChromeOptions; 868 | excludeSwitches(...var_args: string[]): ChromeOptions; 869 | addExtensions(...var_args: any[]): ChromeOptions; 870 | setChromeBinaryPath(path: string): ChromeOptions; 871 | detachDriver(detach: boolean): ChromeOptions; 872 | setUserPreferences(prefs: any): ChromeOptions; 873 | setLoggingPrefs(prefs: WebDriverLoggingPreferences): ChromeOptions; 874 | setPerfLoggingPrefs(prefs: perfLoggingPrefs): ChromeOptions; 875 | setLocalState(state: any): ChromeOptions; 876 | androidActivity(name: string): ChromeOptions; 877 | androidDeviceSerial(serial: string): ChromeOptions; 878 | androidChrome(): ChromeOptions; 879 | androidPackage(pkg: string): ChromeOptions; 880 | androidProcess(processName: string): ChromeOptions; 881 | androidUseRunningApp(useRunning: boolean): ChromeOptions; 882 | setChromeLogFile(path: string): ChromeOptions; 883 | setProxy(proxy: proxyConfig): ChromeOptions; 884 | toCapabilities(opt_capabilities?: WebDriverCapabilities): WebDriverCapabilities; 885 | toJSON(): optionsValues; 886 | } 887 | 888 | declare class ChromeServiceBuilder { 889 | constructor(opt_exe?: string): ChromeServiceBuilder; 890 | usingPort(port: number): ChromeServiceBuilder; 891 | setAdbPort(port: number): ChromeServiceBuilder; 892 | loggingTo(path: string): ChromeServiceBuilder; 893 | enableVerboseLogging(): ChromeServiceBuilder; 894 | setNumHttpThreads(n: number): ChromeServiceBuilder; 895 | setUrlBasePath(path: string): ChromeServiceBuilder; 896 | setStdio(config: string): ChromeServiceBuilder; 897 | setStdio(config: any[]): ChromeServiceBuilder; 898 | withEnvironment(env: { [key: string]: string }): ChromeServiceBuilder; 899 | build(): any; 900 | } 901 | 902 | declare module 'selenium-webdriver/chrome' { 903 | declare type WebDriverChrome = { 904 | Driver: WebDriverClass, 905 | Options: ChromeOptions, 906 | ServiceBuilder: ChromeServiceBuilder, 907 | getDefaultService(): any, 908 | setDefaultService(service: any): void 909 | } 910 | declare var exports: WebDriverChrome; 911 | } 912 | 913 | // /// FIREFOX 914 | 915 | declare class FirefoxBinary { 916 | constructor(opt_exe?: string): FirefoxBinary; 917 | addArguments(...var_args: string[]): void; 918 | launch(profile: string): WebDriverPromise; 919 | kill(): WebDriverPromise; 920 | } 921 | 922 | declare class FirefoxOptions { 923 | constructor(): FirefoxOptions; 924 | setProfile(profile: string): FirefoxOptions; 925 | setProfile(profile: FirefoxProfile): FirefoxOptions; 926 | setBinary(binary: string): FirefoxOptions; 927 | setBinary(binary: FirefoxBinary): FirefoxOptions; 928 | setLoggingPreferences(prefs: WebDriverLoggingPreferences): FirefoxOptions; 929 | setProxy(proxy: proxyConfig): FirefoxOptions; 930 | toCapabilities(opt_remote?: any): WebDriverCapabilities; 931 | } 932 | 933 | declare class FirefoxProfile { 934 | constructor(opt_dir?: string): FirefoxProfile; 935 | addExtension(extension: string): void; 936 | setPreference(key: string, value: string): void; 937 | setPreference(key: string, value: number): void; 938 | setPreference(key: string, value: boolean): void; 939 | getPreference(key: string): any; 940 | getPort(): number; 941 | setPort(port: number): void; 942 | acceptUntrustedCerts(): boolean; 943 | setAcceptUntrustedCerts(value: boolean): void; 944 | setAssumeUntrustedCertIssuer(value: boolean): void; 945 | assumeUntrustedCertIssuer(): boolean; 946 | setNativeEventsEnabled(enabled: boolean): void; 947 | nativeEventsEnabled(): boolean; 948 | writeToDisk(opt_excludeWebDriverExt?: boolean): WebDriverPromise; 949 | encode(): WebDriverPromise; 950 | } 951 | 952 | declare module 'selenium-webdriver/firefox' { 953 | declare type WebDriverFirefox = { 954 | Binary: FirefoxBinary, 955 | Driver: WebDriverClass, 956 | Options: FirefoxOptions, 957 | Profile: FirefoxProfile 958 | } 959 | 960 | declare var exports: WebDriverFirefox; 961 | } 962 | 963 | // //// EXECUTORS 964 | 965 | declare module 'selenium-webdriver/executors' { 966 | declare type WebDriverExecutors = { 967 | createExecutor(url: string): WebDriverCommandExecutor, 968 | createExecutor(url: WebDriverPromise): WebDriverCommandExecutor 969 | } 970 | declare var exports: WebDriverExecutors 971 | } 972 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webdriver-mocha-async-await-example", 3 | "version": "2.0.0", 4 | "description": "Using Mocha, Selenium Webdriver, and Babel together to provide async / await to browser e2e tests", 5 | "engines": { 6 | "node": ">7.5.0" 7 | }, 8 | "scripts": { 9 | "test": "./node_modules/.bin/_mocha", 10 | "install": "./node_modules/.bin/selenium-standalone install", 11 | "start": "./node_modules/.bin/selenium-standalone start", 12 | "lint": "./node_modules/.bin/eslint .", 13 | "flow": "flow; test $? -eq 0 -o $? -eq 2" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/airware/webdriver-mocha-async-await-example.git" 18 | }, 19 | "author": "Airware", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/airware/webdriver-mocha-async-await-example/issues" 23 | }, 24 | "homepage": "https://github.com/airware/webdriver-mocha-async-await-example#readme", 25 | "dependencies": { 26 | "babel-plugin-transform-flow-strip-types": "^6.22.0", 27 | "babel-plugin-transform-object-rest-spread": "^6.23.0", 28 | "babel-preset-env": "^1.1.10", 29 | "babel-register": "^6.16.3", 30 | "chai": "^3.5.0", 31 | "mocha": "^3.1.2", 32 | "selenium-standalone": "^5.7.2", 33 | "selenium-webdriver": "^3.1.0" 34 | }, 35 | "devDependencies": { 36 | "babel-eslint": "^7.1.1", 37 | "eslint": "^3.16.1", 38 | "eslint-config-standard": "^6.2.1", 39 | "eslint-plugin-flowtype": "^2.30.0", 40 | "eslint-plugin-promise": "^3.4.2", 41 | "eslint-plugin-standard": "^2.0.1", 42 | "flow-bin": "^0.40.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/lib/DriverBuilder.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import webdriver from 'selenium-webdriver' 3 | 4 | export default class DriverBuilder { 5 | driver: WebDriverClass 6 | 7 | constructor () { 8 | const builder = new webdriver.Builder().usingServer('http://localhost:4444/wd/hub') 9 | // $FlowIssue getting chrome capabilities as method is a-ok 10 | const capabilities = webdriver.Capabilities['chrome']() 11 | builder.withCapabilities(capabilities) 12 | this.driver = builder.build() 13 | } 14 | 15 | async quit (): Promise { 16 | return this.driver.quit() 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/lib/driver-utils.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | const baseUrl = 'https://saucelabs.com/' 3 | 4 | export default { 5 | async goToHome (driver: WebDriverClass): Promise { 6 | return driver.get(baseUrl) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/pageobjects/BasePage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { until } from 'selenium-webdriver' 3 | 4 | async function waitForLocated (driver: WebDriverClass, locator: WebDriverLocator, retries?: number = 3): Promise { 5 | try { 6 | await driver.wait(until.elementLocated(locator), 7000) 7 | } catch (err) { 8 | if (retries === 0) { 9 | throw new Error(`Still not able to locate element ${locator.toString()} after maximum retries, Error message: ${err.message.toString()}`) 10 | } 11 | await driver.sleep(250) 12 | return waitForLocated(driver, locator, retries - 1) 13 | } 14 | } 15 | 16 | async function waitForVisible (driver: WebDriverClass, locator: WebDriverLocator, retries?: number = 3): Promise { 17 | try { 18 | const element = await driver.findElement(locator) 19 | await driver.wait(until.elementIsVisible(element), 7000) 20 | } catch (err) { 21 | if (retries === 0) { 22 | throw new Error(`Element ${locator.toString()} still not visible after maximum retries, Error message: ${err.message.toString()}`) 23 | } 24 | await driver.sleep(250) 25 | return waitForVisible(driver, locator, retries - 1) 26 | } 27 | } 28 | 29 | export default class BasePage { 30 | driver: WebDriverClass 31 | 32 | constructor (webdriver: WebDriverClass) { 33 | this.driver = webdriver 34 | } 35 | 36 | async waitForDisplayed (locator: WebDriverLocator, retries?: number = 3): Promise { 37 | await waitForLocated(this.driver, locator, retries) 38 | await waitForVisible(this.driver, locator, retries) 39 | return this.driver.findElement(locator) 40 | } 41 | 42 | async sendKeys (locator: WebDriverLocator, keys: string, retries?: number = 1): Promise { 43 | try { 44 | const element = await this.driver.findElement(locator) 45 | await element.click() 46 | await element.clear() 47 | await element.sendKeys(keys) 48 | return 49 | } catch (err) { 50 | if (retries === 0) { 51 | throw new Error(`Unable to send keys to ${locator.toString()} after maximum retries, error : ${err.message}`) 52 | } 53 | await this.driver.sleep(250) 54 | return this.sendKeys(locator, keys, retries - 1) 55 | } 56 | } 57 | 58 | async getText (locator: WebDriverLocator, retries?: number = 1): Promise { 59 | try { 60 | const element = await this.driver.findElement(locator) 61 | const text = await element.getText() 62 | return text 63 | } catch (err) { 64 | if (retries === 0) { 65 | throw new Error(`Unable to get ${locator.toString()} text after maximum retries, error : ${err.message}`) 66 | } 67 | await this.driver.sleep(250) 68 | return this.getText(locator, retries - 1) 69 | } 70 | } 71 | 72 | async click (locator: WebDriverLocator, retries?: number = 1) { 73 | try { 74 | const element = await this.driver.findElement(locator) 75 | await element.click() 76 | return 77 | } catch (err) { 78 | if (retries === 0) { 79 | throw new Error(`Still not able to click ${locator.toString()} after maximum retries, Error message: ${err.message.toString()}`) 80 | } 81 | await this.driver.sleep(250) 82 | return this.click(locator, retries - 1) 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/pageobjects/HomePage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { By } from 'selenium-webdriver' 3 | import BasePage from './BasePage' 4 | 5 | const SEARCH_BUTTON = By.css('#site-header button.hidden-sm-down') 6 | const TITLE = By.css('.site-content h1') 7 | const SEARCH_BOX = By.css('#site-header form input[type="text"]') 8 | const SEARCH_SUBMIT_BUTTON = By.css('#site-header form button[type="submit"]') 9 | 10 | export default class HomePage extends BasePage { 11 | 12 | async isLoaded () { 13 | await this.waitForDisplayed(TITLE) 14 | await this.waitForDisplayed(SEARCH_BUTTON) 15 | } 16 | 17 | async getTitle () { 18 | return this.getText(TITLE) 19 | } 20 | 21 | async search (searchTerm: string) { 22 | await this.click(SEARCH_BUTTON) 23 | await this.waitForDisplayed(SEARCH_BOX) 24 | await this.waitForDisplayed(SEARCH_SUBMIT_BUTTON) 25 | await this.sendKeys(SEARCH_BOX, searchTerm) 26 | await this.click(SEARCH_SUBMIT_BUTTON) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/pageobjects/SearchResultsPage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { By } from 'selenium-webdriver' 4 | import BasePage from './BasePage' 5 | 6 | const SEARCH_TITLE = By.css('.container .row h2') 7 | 8 | export default class SearchResultsPage extends BasePage { 9 | 10 | async isLoaded () { 11 | await this.waitForDisplayed(SEARCH_TITLE) 12 | } 13 | 14 | async getTitle () { 15 | return this.getText(SEARCH_TITLE) 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /test/AcceptanceTest.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { assert } from 'chai' 3 | 4 | import HomePage from './../src/pageobjects/HomePage' 5 | import SearchResultsPage from './../src/pageobjects/SearchResultsPage' 6 | 7 | import DriverBuilder from './../src/lib/DriverBuilder' 8 | import driverutils from './../src/lib/driver-utils' 9 | 10 | describe('Acceptance Tests', function () { 11 | let driverBuilder 12 | let driver 13 | 14 | beforeEach(async function () { 15 | driverBuilder = new DriverBuilder() 16 | driver = driverBuilder.driver 17 | await driverutils.goToHome(driver) 18 | }) 19 | 20 | it('Loads the home page', async function () { 21 | const homePage = new HomePage(driver) 22 | await homePage.isLoaded() 23 | const title = await homePage.getTitle() 24 | assert.strictEqual(title, 'TESTING AT THE\nSPEED OF AWESOME.', 'Title should match expected tagline') 25 | }) 26 | 27 | it('Searches for a term', async function () { 28 | const homePage = new HomePage(driver) 29 | await homePage.isLoaded() 30 | await homePage.search('Airware') 31 | 32 | const searchResultsPage = new SearchResultsPage(driver) 33 | await searchResultsPage.isLoaded() 34 | const title = await searchResultsPage.getTitle() 35 | assert.strictEqual(title, 'Search Results for Airware', 'Title should reference search term') 36 | }) 37 | 38 | afterEach(async function () { 39 | await driverBuilder.quit() 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --timeout 999999 2 | --ui tdd 3 | --full-trace 4 | --recursive 5 | --compilers js:babel-register 6 | --------------------------------------------------------------------------------