1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | 'use strict'
|
27 |
|
28 | const path = require('path')
|
29 | const cmd = require('./command')
|
30 | const error = require('./error')
|
31 | const logging = require('./logging')
|
32 | const promise = require('./promise')
|
33 | const { Session } = require('./session')
|
34 | const { WebElement } = require('./webdriver')
|
35 |
|
36 | const getAttribute = requireAtom(
|
37 | 'get-attribute.js',
|
38 | '//javascript/node/selenium-webdriver/lib/atoms:get-attribute.js'
|
39 | )
|
40 | const isDisplayed = requireAtom(
|
41 | 'is-displayed.js',
|
42 | '//javascript/node/selenium-webdriver/lib/atoms:is-displayed.js'
|
43 | )
|
44 | const findElements = requireAtom(
|
45 | 'find-elements.js',
|
46 | '//javascript/node/selenium-webdriver/lib/atoms:find-elements.js'
|
47 | )
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 | function requireAtom(module, bazelTarget) {
|
55 | try {
|
56 | return require('./atoms/' + module)
|
57 | } catch (ex) {
|
58 | try {
|
59 | const file = bazelTarget.slice(2).replace(':', '/')
|
60 | console.log(`../../../bazel-bin/${file}`)
|
61 | return require(path.resolve(`../../../bazel-bin/${file}`))
|
62 | } catch (ex2) {
|
63 | console.log(ex2)
|
64 | throw Error(
|
65 | `Failed to import atoms module ${module}. If running in dev mode, you` +
|
66 | ` need to run \`bazel build ${bazelTarget}\` from the project` +
|
67 | `root: ${ex}`
|
68 | )
|
69 | }
|
70 | }
|
71 | }
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 | function headersToString(headers) {
|
79 | const ret = []
|
80 | headers.forEach(function (value, name) {
|
81 | ret.push(`${name.toLowerCase()}: ${value}`)
|
82 | })
|
83 | return ret.join('\n')
|
84 | }
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 | class Request {
|
93 | |
94 |
|
95 |
|
96 |
|
97 |
|
98 | constructor(method, path, opt_data) {
|
99 | this.method = method
|
100 | this.path = path
|
101 | this.data = opt_data
|
102 | this.headers = new Map([
|
103 | ['Accept', 'application/json; charset=utf-8'],
|
104 | ])
|
105 | }
|
106 |
|
107 |
|
108 | toString() {
|
109 | let ret = `${this.method} ${this.path} HTTP/1.1\n`
|
110 | ret += headersToString(this.headers) + '\n\n'
|
111 | if (this.data) {
|
112 | ret += JSON.stringify(this.data)
|
113 | }
|
114 | return ret
|
115 | }
|
116 | }
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 | class Response {
|
123 | |
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 | constructor(status, headers, body) {
|
130 | this.status = status
|
131 | this.body = body
|
132 | this.headers = new Map()
|
133 | for (let header in headers) {
|
134 | this.headers.set(header.toLowerCase(), headers[header])
|
135 | }
|
136 | }
|
137 |
|
138 |
|
139 | toString() {
|
140 | let ret = `HTTP/1.1 ${this.status}\n${headersToString(this.headers)}\n\n`
|
141 | if (this.body) {
|
142 | ret += this.body
|
143 | }
|
144 | return ret
|
145 | }
|
146 | }
|
147 |
|
148 |
|
149 | const Atom = {
|
150 | GET_ATTRIBUTE: getAttribute,
|
151 | IS_DISPLAYED: isDisplayed,
|
152 | FIND_ELEMENTS: findElements,
|
153 | }
|
154 |
|
155 | const LOG = logging.getLogger('webdriver.http')
|
156 |
|
157 | function post(path) {
|
158 | return resource('POST', path)
|
159 | }
|
160 | function del(path) {
|
161 | return resource('DELETE', path)
|
162 | }
|
163 | function get(path) {
|
164 | return resource('GET', path)
|
165 | }
|
166 | function resource(method, path) {
|
167 | return { method: method, path: path }
|
168 | }
|
169 |
|
170 |
|
171 | var CommandSpec
|
172 |
|
173 |
|
174 | var CommandTransformer
|
175 |
|
176 | class InternalTypeError extends TypeError {}
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | function toExecuteAtomCommand(command, atom, ...params) {
|
184 | if (typeof atom !== 'function') {
|
185 | throw new InternalTypeError('atom is not a function: ' + typeof atom)
|
186 | }
|
187 |
|
188 | return new cmd.Command(cmd.Name.EXECUTE_SCRIPT)
|
189 | .setParameter('sessionId', command.getParameter('sessionId'))
|
190 | .setParameter('script', `return (${atom}).apply(null, arguments)`)
|
191 | .setParameter(
|
192 | 'args',
|
193 | params.map((param) => command.getParameter(param))
|
194 | )
|
195 | }
|
196 |
|
197 |
|
198 | const COMMAND_MAP = new Map([
|
199 | [cmd.Name.GET_SERVER_STATUS, get('/status')],
|
200 | [cmd.Name.NEW_SESSION, post('/session')],
|
201 | [cmd.Name.GET_SESSIONS, get('/sessions')],
|
202 | [cmd.Name.QUIT, del('/session/:sessionId')],
|
203 | [cmd.Name.CLOSE, del('/session/:sessionId/window')],
|
204 | [
|
205 | cmd.Name.GET_CURRENT_WINDOW_HANDLE,
|
206 | get('/session/:sessionId/window_handle'),
|
207 | ],
|
208 | [cmd.Name.GET_WINDOW_HANDLES, get('/session/:sessionId/window_handles')],
|
209 | [cmd.Name.GET_CURRENT_URL, get('/session/:sessionId/url')],
|
210 | [cmd.Name.GET, post('/session/:sessionId/url')],
|
211 | [cmd.Name.GO_BACK, post('/session/:sessionId/back')],
|
212 | [cmd.Name.GO_FORWARD, post('/session/:sessionId/forward')],
|
213 | [cmd.Name.REFRESH, post('/session/:sessionId/refresh')],
|
214 | [cmd.Name.ADD_COOKIE, post('/session/:sessionId/cookie')],
|
215 | [cmd.Name.GET_ALL_COOKIES, get('/session/:sessionId/cookie')],
|
216 | [cmd.Name.DELETE_ALL_COOKIES, del('/session/:sessionId/cookie')],
|
217 | [cmd.Name.DELETE_COOKIE, del('/session/:sessionId/cookie/:name')],
|
218 | [cmd.Name.FIND_ELEMENT, post('/session/:sessionId/element')],
|
219 | [cmd.Name.FIND_ELEMENTS, post('/session/:sessionId/elements')],
|
220 | [cmd.Name.GET_ACTIVE_ELEMENT, post('/session/:sessionId/element/active')],
|
221 | [
|
222 | cmd.Name.FIND_CHILD_ELEMENT,
|
223 | post('/session/:sessionId/element/:id/element'),
|
224 | ],
|
225 | [
|
226 | cmd.Name.FIND_CHILD_ELEMENTS,
|
227 | post('/session/:sessionId/element/:id/elements'),
|
228 | ],
|
229 | [cmd.Name.CLEAR_ELEMENT, post('/session/:sessionId/element/:id/clear')],
|
230 | [cmd.Name.CLICK_ELEMENT, post('/session/:sessionId/element/:id/click')],
|
231 | [
|
232 | cmd.Name.SEND_KEYS_TO_ELEMENT,
|
233 | post('/session/:sessionId/element/:id/value'),
|
234 | ],
|
235 | [cmd.Name.SUBMIT_ELEMENT, post('/session/:sessionId/element/:id/submit')],
|
236 | [cmd.Name.GET_ELEMENT_TEXT, get('/session/:sessionId/element/:id/text')],
|
237 | [
|
238 | cmd.Name.GET_COMPUTED_ROLE,
|
239 | get('/session/:sessionId/element/:id/computedrole'),
|
240 | ],
|
241 | [
|
242 | cmd.Name.GET_COMPUTED_LABEL,
|
243 | get('/session/:sessionId/element/:id/computedlabel'),
|
244 | ],
|
245 | [cmd.Name.GET_ELEMENT_TAG_NAME, get('/session/:sessionId/element/:id/name')],
|
246 | [
|
247 | cmd.Name.IS_ELEMENT_SELECTED,
|
248 | get('/session/:sessionId/element/:id/selected'),
|
249 | ],
|
250 | [cmd.Name.IS_ELEMENT_ENABLED, get('/session/:sessionId/element/:id/enabled')],
|
251 | [
|
252 | cmd.Name.IS_ELEMENT_DISPLAYED,
|
253 | get('/session/:sessionId/element/:id/displayed'),
|
254 | ],
|
255 | [
|
256 | cmd.Name.GET_ELEMENT_LOCATION,
|
257 | get('/session/:sessionId/element/:id/location'),
|
258 | ],
|
259 | [cmd.Name.GET_ELEMENT_SIZE, get('/session/:sessionId/element/:id/size')],
|
260 | [
|
261 | cmd.Name.GET_ELEMENT_ATTRIBUTE,
|
262 | get('/session/:sessionId/element/:id/attribute/:name'),
|
263 | ],
|
264 | [
|
265 | cmd.Name.GET_ELEMENT_PROPERTY,
|
266 | get('/session/:sessionId/element/:id/property/:name'),
|
267 | ],
|
268 | [
|
269 | cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY,
|
270 | get('/session/:sessionId/element/:id/css/:propertyName'),
|
271 | ],
|
272 | [
|
273 | cmd.Name.TAKE_ELEMENT_SCREENSHOT,
|
274 | get('/session/:sessionId/element/:id/screenshot'),
|
275 | ],
|
276 | [cmd.Name.SWITCH_TO_WINDOW, post('/session/:sessionId/window')],
|
277 | [
|
278 | cmd.Name.MAXIMIZE_WINDOW,
|
279 | post('/session/:sessionId/window/current/maximize'),
|
280 | ],
|
281 | [
|
282 | cmd.Name.GET_WINDOW_POSITION,
|
283 | get('/session/:sessionId/window/current/position'),
|
284 | ],
|
285 | [
|
286 | cmd.Name.SET_WINDOW_POSITION,
|
287 | post('/session/:sessionId/window/current/position'),
|
288 | ],
|
289 | [cmd.Name.GET_WINDOW_SIZE, get('/session/:sessionId/window/current/size')],
|
290 | [cmd.Name.SET_WINDOW_SIZE, post('/session/:sessionId/window/current/size')],
|
291 | [cmd.Name.SWITCH_TO_FRAME, post('/session/:sessionId/frame')],
|
292 | [cmd.Name.SWITCH_TO_FRAME_PARENT, post('/session/:sessionId/frame/parent')],
|
293 | [cmd.Name.GET_PAGE_SOURCE, get('/session/:sessionId/source')],
|
294 | [cmd.Name.GET_TITLE, get('/session/:sessionId/title')],
|
295 | [cmd.Name.EXECUTE_SCRIPT, post('/session/:sessionId/execute')],
|
296 | [cmd.Name.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute_async')],
|
297 | [cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
|
298 | [cmd.Name.GET_TIMEOUT, get('/session/:sessionId/timeouts')],
|
299 | [cmd.Name.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
|
300 | [cmd.Name.ACCEPT_ALERT, post('/session/:sessionId/accept_alert')],
|
301 | [cmd.Name.DISMISS_ALERT, post('/session/:sessionId/dismiss_alert')],
|
302 | [cmd.Name.GET_ALERT_TEXT, get('/session/:sessionId/alert_text')],
|
303 | [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert_text')],
|
304 | [cmd.Name.GET_LOG, post('/session/:sessionId/log')],
|
305 | [cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/log/types')],
|
306 | [cmd.Name.GET_SESSION_LOGS, post('/logs')],
|
307 | [cmd.Name.UPLOAD_FILE, post('/session/:sessionId/se/file')],
|
308 | ])
|
309 |
|
310 | /** @const {!Map<string, (CommandSpec|CommandTransformer)>} */
|
311 | const W3C_COMMAND_MAP = new Map([
|
312 |
|
313 | [cmd.Name.GET_SERVER_STATUS, get('/status')],
|
314 | // Session management.
|
315 | [cmd.Name.NEW_SESSION, post('/session')],
|
316 | [cmd.Name.QUIT, del('/session/:sessionId')],
|
317 | [cmd.Name.GET_TIMEOUT, get('/session/:sessionId/timeouts')],
|
318 | [cmd.Name.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
|
319 | // Navigation.
|
320 | [cmd.Name.GET_CURRENT_URL, get('/session/:sessionId/url')],
|
321 | [cmd.Name.GET, post('/session/:sessionId/url')],
|
322 | [cmd.Name.GO_BACK, post('/session/:sessionId/back')],
|
323 | [cmd.Name.GO_FORWARD, post('/session/:sessionId/forward')],
|
324 | [cmd.Name.REFRESH, post('/session/:sessionId/refresh')],
|
325 | // Page inspection.
|
326 | [cmd.Name.GET_PAGE_SOURCE, get('/session/:sessionId/source')],
|
327 | [cmd.Name.GET_TITLE, get('/session/:sessionId/title')],
|
328 | // Script execution.
|
329 | [cmd.Name.EXECUTE_SCRIPT, post('/session/:sessionId/execute/sync')],
|
330 | [cmd.Name.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute/async')],
|
331 | // Frame selection.
|
332 | [cmd.Name.SWITCH_TO_FRAME, post('/session/:sessionId/frame')],
|
333 | [cmd.Name.SWITCH_TO_FRAME_PARENT, post('/session/:sessionId/frame/parent')],
|
334 | // Window management.
|
335 | [cmd.Name.GET_CURRENT_WINDOW_HANDLE, get('/session/:sessionId/window')],
|
336 | [cmd.Name.CLOSE, del('/session/:sessionId/window')],
|
337 | [cmd.Name.SWITCH_TO_WINDOW, post('/session/:sessionId/window')],
|
338 | [cmd.Name.SWITCH_TO_NEW_WINDOW, post('/session/:sessionId/window/new')],
|
339 | [cmd.Name.GET_WINDOW_HANDLES, get('/session/:sessionId/window/handles')],
|
340 | [cmd.Name.GET_WINDOW_RECT, get('/session/:sessionId/window/rect')],
|
341 | [cmd.Name.SET_WINDOW_RECT, post('/session/:sessionId/window/rect')],
|
342 | [cmd.Name.MAXIMIZE_WINDOW, post('/session/:sessionId/window/maximize')],
|
343 | [cmd.Name.MINIMIZE_WINDOW, post('/session/:sessionId/window/minimize')],
|
344 | [cmd.Name.FULLSCREEN_WINDOW, post('/session/:sessionId/window/fullscreen')],
|
345 | // Actions.
|
346 | [cmd.Name.ACTIONS, post('/session/:sessionId/actions')],
|
347 | [cmd.Name.CLEAR_ACTIONS, del('/session/:sessionId/actions')],
|
348 | // Locating elements.
|
349 | [cmd.Name.GET_ACTIVE_ELEMENT, get('/session/:sessionId/element/active')],
|
350 | [cmd.Name.FIND_ELEMENT, post('/session/:sessionId/element')],
|
351 | [cmd.Name.FIND_ELEMENTS, post('/session/:sessionId/elements')],
|
352 | [
|
353 | cmd.Name.FIND_ELEMENTS_RELATIVE,
|
354 | (cmd) => {
|
355 | return toExecuteAtomCommand(cmd, Atom.FIND_ELEMENTS, 'args')
|
356 | },
|
357 | ],
|
358 | [
|
359 | cmd.Name.FIND_CHILD_ELEMENT,
|
360 | post('/session/:sessionId/element/:id/element'),
|
361 | ],
|
362 | [
|
363 | cmd.Name.FIND_CHILD_ELEMENTS,
|
364 | post('/session/:sessionId/element/:id/elements'),
|
365 | ],
|
366 |
|
367 | [cmd.Name.GET_ELEMENT_TAG_NAME, get('/session/:sessionId/element/:id/name')],
|
368 | [
|
369 | cmd.Name.GET_ELEMENT_PROPERTY,
|
370 | get('/session/:sessionId/element/:id/property/:name'),
|
371 | ],
|
372 | [
|
373 | cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY,
|
374 | get('/session/:sessionId/element/:id/css/:propertyName'),
|
375 | ],
|
376 | [cmd.Name.GET_ELEMENT_RECT, get('/session/:sessionId/element/:id/rect')],
|
377 | [cmd.Name.CLEAR_ELEMENT, post('/session/:sessionId/element/:id/clear')],
|
378 | [cmd.Name.CLICK_ELEMENT, post('/session/:sessionId/element/:id/click')],
|
379 | [
|
380 | cmd.Name.SEND_KEYS_TO_ELEMENT,
|
381 | post('/session/:sessionId/element/:id/value'),
|
382 | ],
|
383 | [cmd.Name.GET_ELEMENT_TEXT, get('/session/:sessionId/element/:id/text')],
|
384 | [
|
385 | cmd.Name.GET_COMPUTED_ROLE,
|
386 | get('/session/:sessionId/element/:id/computedrole'),
|
387 | ],
|
388 | [
|
389 | cmd.Name.GET_COMPUTED_LABEL,
|
390 | get('/session/:sessionId/element/:id/computedlabel'),
|
391 | ],
|
392 | [cmd.Name.IS_ELEMENT_ENABLED, get('/session/:sessionId/element/:id/enabled')],
|
393 | [
|
394 | cmd.Name.GET_ELEMENT_ATTRIBUTE,
|
395 | (cmd) => {
|
396 | return toExecuteAtomCommand(cmd, Atom.GET_ATTRIBUTE, 'id', 'name')
|
397 | },
|
398 | ],
|
399 | [
|
400 | cmd.Name.IS_ELEMENT_DISPLAYED,
|
401 | (cmd) => {
|
402 | return toExecuteAtomCommand(cmd, Atom.IS_DISPLAYED, 'id')
|
403 | },
|
404 | ],
|
405 |
|
406 | [cmd.Name.GET_ALL_COOKIES, get('/session/:sessionId/cookie')],
|
407 | [cmd.Name.ADD_COOKIE, post('/session/:sessionId/cookie')],
|
408 | [cmd.Name.DELETE_ALL_COOKIES, del('/session/:sessionId/cookie')],
|
409 | [cmd.Name.GET_COOKIE, get('/session/:sessionId/cookie/:name')],
|
410 | [cmd.Name.DELETE_COOKIE, del('/session/:sessionId/cookie/:name')],
|
411 | // Alert management.
|
412 | [cmd.Name.ACCEPT_ALERT, post('/session/:sessionId/alert/accept')],
|
413 | [cmd.Name.DISMISS_ALERT, post('/session/:sessionId/alert/dismiss')],
|
414 | [cmd.Name.GET_ALERT_TEXT, get('/session/:sessionId/alert/text')],
|
415 | [cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert/text')],
|
416 | // Screenshots.
|
417 | [cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
|
418 | [
|
419 | cmd.Name.TAKE_ELEMENT_SCREENSHOT,
|
420 | get('/session/:sessionId/element/:id/screenshot'),
|
421 | ],
|
422 | // print page.
|
423 | [cmd.Name.PRINT_PAGE, post('/session/:sessionId/print')],
|
424 | // Log extensions.
|
425 | [cmd.Name.GET_LOG, post('/session/:sessionId/se/log')],
|
426 | [cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/se/log/types')],
|
427 | ])
|
428 |
|
429 | /**
|
430 | * Handles sending HTTP messages to a remote end.
|
431 | *
|
432 | * @interface
|
433 | */
|
434 | class Client {
|
435 | |
436 |
|
437 |
|
438 |
|
439 |
|
440 |
|
441 |
|
442 |
|
443 |
|
444 | send(httpRequest) {}
|
445 | }
|
446 |
|
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 |
|
455 | function buildRequest(customCommands, w3c, command) {
|
456 | LOG.finest(() => `Translating command: ${command.getName()}`)
|
457 | let spec = customCommands && customCommands.get(command.getName())
|
458 | if (spec) {
|
459 | return toHttpRequest(spec)
|
460 | }
|
461 |
|
462 | if (w3c) {
|
463 | spec = W3C_COMMAND_MAP.get(command.getName())
|
464 | if (typeof spec === 'function') {
|
465 | LOG.finest(() => `Transforming command for W3C: ${command.getName()}`)
|
466 | let newCommand = spec(command)
|
467 | return buildRequest(customCommands, w3c, newCommand)
|
468 | } else if (spec) {
|
469 | return toHttpRequest(spec)
|
470 | }
|
471 | }
|
472 |
|
473 | spec = COMMAND_MAP.get(command.getName())
|
474 | if (spec) {
|
475 | return toHttpRequest(spec)
|
476 | }
|
477 | throw new error.UnknownCommandError(
|
478 | 'Unrecognized command: ' + command.getName()
|
479 | )
|
480 |
|
481 | |
482 |
|
483 |
|
484 |
|
485 | function toHttpRequest(resource) {
|
486 | LOG.finest(() => `Building HTTP request: ${JSON.stringify(resource)}`)
|
487 | let parameters = command.getParameters()
|
488 | let path = buildPath(resource.path, parameters)
|
489 | return new Request(resource.method, path, parameters)
|
490 | }
|
491 | }
|
492 |
|
493 | const CLIENTS =
|
494 | new WeakMap()
|
495 |
|
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 |
|
505 |
|
506 |
|
507 |
|
508 |
|
509 | class Executor {
|
510 | |
511 |
|
512 |
|
513 |
|
514 |
|
515 | constructor(client) {
|
516 | CLIENTS.set(this, client)
|
517 |
|
518 | |
519 |
|
520 |
|
521 |
|
522 |
|
523 |
|
524 |
|
525 | this.w3c = false
|
526 |
|
527 |
|
528 | this.customCommands_ = null
|
529 |
|
530 |
|
531 | this.log_ = logging.getLogger('webdriver.http.Executor')
|
532 | }
|
533 |
|
534 | |
535 |
|
536 |
|
537 |
|
538 |
|
539 |
|
540 |
|
541 |
|
542 |
|
543 |
|
544 |
|
545 |
|
546 |
|
547 | defineCommand(name, method, path) {
|
548 | if (!this.customCommands_) {
|
549 | this.customCommands_ = new Map()
|
550 | }
|
551 | this.customCommands_.set(name, { method, path })
|
552 | }
|
553 |
|
554 |
|
555 | async execute(command) {
|
556 | let request = buildRequest(this.customCommands_, this.w3c, command)
|
557 | this.log_.finer(() => `>>> ${request.method} ${request.path}`)
|
558 |
|
559 | let client = CLIENTS.get(this)
|
560 | if (promise.isPromise(client)) {
|
561 | client = await client
|
562 | CLIENTS.set(this, client)
|
563 | }
|
564 |
|
565 | let response = await client.send(request)
|
566 | this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`)
|
567 |
|
568 | let httpResponse = (response)
|
569 | let { isW3C, value } = parseHttpResponse(command, httpResponse)
|
570 |
|
571 | if (command.getName() === cmd.Name.NEW_SESSION) {
|
572 | if (!value || !value.sessionId) {
|
573 | throw new error.WebDriverError(
|
574 | `Unable to parse new session response: ${response.body}`
|
575 | )
|
576 | }
|
577 |
|
578 |
|
579 |
|
580 | if (command.getName() === cmd.Name.NEW_SESSION) {
|
581 | this.w3c = this.w3c || isW3C
|
582 | }
|
583 |
|
584 |
|
585 | let capabilities = value.capabilities || value.value
|
586 | return new Session(
|
587 | (value).sessionId,
|
588 | capabilities
|
589 | )
|
590 | }
|
591 |
|
592 | return typeof value === 'undefined' ? null : value
|
593 | }
|
594 | }
|
595 |
|
596 |
|
597 |
|
598 |
|
599 |
|
600 | function tryParse(str) {
|
601 | try {
|
602 | return JSON.parse(str)
|
603 | } catch (ignored) {
|
604 |
|
605 | }
|
606 | }
|
607 |
|
608 |
|
609 |
|
610 |
|
611 |
|
612 |
|
613 |
|
614 |
|
615 |
|
616 |
|
617 |
|
618 |
|
619 |
|
620 | function parseHttpResponse(command, httpResponse) {
|
621 | if (httpResponse.status < 200) {
|
622 |
|
623 | throw new error.WebDriverError(`Unexpected HTTP response:\n${httpResponse}`)
|
624 | }
|
625 |
|
626 | let parsed = tryParse(httpResponse.body)
|
627 | if (parsed && typeof parsed === 'object') {
|
628 | let value = parsed.value
|
629 | let isW3C =
|
630 | value !== null &&
|
631 | typeof value === 'object' &&
|
632 | typeof parsed.status === 'undefined'
|
633 |
|
634 | if (!isW3C) {
|
635 | error.checkLegacyResponse(parsed)
|
636 |
|
637 |
|
638 |
|
639 | if (command.getName() === cmd.Name.NEW_SESSION) {
|
640 | value = parsed
|
641 | }
|
642 | } else if (httpResponse.status > 399) {
|
643 | error.throwDecodedError(value)
|
644 | }
|
645 |
|
646 | return { isW3C, value }
|
647 | }
|
648 |
|
649 | if (parsed !== undefined) {
|
650 | return { isW3C: false, value: parsed }
|
651 | }
|
652 |
|
653 | let value = httpResponse.body.replace(/\r\n/g, '\n')
|
654 |
|
655 |
|
656 |
|
657 | if (httpResponse.status == 404) {
|
658 | throw new error.UnsupportedOperationError(command.getName() + ': ' + value)
|
659 | } else if (httpResponse.status >= 400) {
|
660 | throw new error.WebDriverError(value)
|
661 | }
|
662 |
|
663 | return { isW3C: false, value: value || null }
|
664 | }
|
665 |
|
666 |
|
667 |
|
668 |
|
669 |
|
670 |
|
671 |
|
672 |
|
673 |
|
674 |
|
675 | function buildPath(path, parameters) {
|
676 | let pathParameters = path.match(/\/:(\w+)\b/g)
|
677 | if (pathParameters) {
|
678 | for (let i = 0; i < pathParameters.length; ++i) {
|
679 | let key = pathParameters[i].substring(2)
|
680 | if (key in parameters) {
|
681 | let value = parameters[key]
|
682 | if (WebElement.isId(value)) {
|
683 |
|
684 |
|
685 | value = WebElement.extractId(value)
|
686 | }
|
687 | path = path.replace(pathParameters[i], '/' + value)
|
688 | delete parameters[key]
|
689 | } else {
|
690 | throw new error.InvalidArgumentError(
|
691 | 'Missing required parameter: ' + key
|
692 | )
|
693 | }
|
694 | }
|
695 | }
|
696 | return path
|
697 | }
|
698 |
|
699 |
|
700 |
|
701 | exports.Executor = Executor
|
702 | exports.Client = Client
|
703 | exports.Request = Request
|
704 | exports.Response = Response
|
705 | exports.buildPath = buildPath
|