@@ -2515,16 +2515,136 @@ class ActionSequence {
2515
2515
* @return {!Promise<void> } a promise that will resolve when all actions have
2516
2516
* been completed.
2517
2517
*/
2518
- perform ( ) {
2518
+ async perform ( ) {
2519
2519
let actions = [
2520
2520
this . keyboard_ ,
2521
2521
this . mouse_ ,
2522
2522
this . touch_
2523
2523
] . filter ( sequence => ! sequence . isIdle ( ) ) ;
2524
- return this . driver_ . execute (
2525
- new command . Command ( command . Name . ACTIONS )
2526
- . setParameter ( 'actions' , actions ) ) ;
2524
+
2525
+ try {
2526
+ await this . driver_ . execute (
2527
+ new command . Command ( command . Name . ACTIONS )
2528
+ . setParameter ( 'actions' , actions ) ) ;
2529
+ } catch ( err ) {
2530
+ if ( ! ( err instanceof error . UnknownCommandError )
2531
+ && ! ( err instanceof error . UnsupportedOperationError ) ) {
2532
+ throw err ;
2533
+ }
2534
+
2535
+ const commands = await translateInputSequences ( actions ) ;
2536
+ for ( let cmd of commands ) {
2537
+ await this . driver_ . execute ( cmd ) ;
2538
+ }
2539
+ }
2540
+ }
2541
+ }
2542
+
2543
+
2544
+ const MODIFIER_KEYS = new Set ( [
2545
+ input . Key . ALT ,
2546
+ input . Key . CONTROL ,
2547
+ input . Key . SHIFT ,
2548
+ input . Key . COMMAND
2549
+ ] ) ;
2550
+
2551
+
2552
+ /**
2553
+ * Translates input sequences to commands against the legacy actions API.
2554
+ * @param {!Array<!input.Sequence> } sequences The input sequences to translate.
2555
+ * @return {!Promise<!Array<command.Command>> } The translated commands.
2556
+ */
2557
+ async function translateInputSequences ( sequences ) {
2558
+ let devices = await toWireValue ( sequences ) ;
2559
+ if ( ! Array . isArray ( devices ) ) {
2560
+ throw TypeError ( `expected an array, got: ${ typeof devices } ` ) ;
2561
+ }
2562
+
2563
+ const commands = [ ] ;
2564
+ const maxLength =
2565
+ devices . reduce ( ( len , device ) => Math . max ( device . actions . length , len ) , 0 ) ;
2566
+ for ( let i = 0 ; i < maxLength ; i ++ ) {
2567
+ let next ;
2568
+ for ( let device of devices ) {
2569
+ if ( device . type === input . DeviceType . POINTER
2570
+ && device . parameters . pointerType !== input . Pointer . Type . MOUSE ) {
2571
+ throw new error . UnsupportedOperationError (
2572
+ `${ device . parameters . pointerType } pointer not supported `
2573
+ + `by the legacy API` ) ;
2574
+ }
2575
+
2576
+ let action = device . actions [ i ] ;
2577
+ if ( ! action || action . type === input . ActionType . PAUSE ) {
2578
+ continue ;
2579
+ }
2580
+
2581
+ if ( next ) {
2582
+ throw new error . UnsupportedOperationError (
2583
+ 'Parallel action sequences are not supported for this browser' ) ;
2584
+ } else {
2585
+ next = action ;
2586
+ }
2587
+
2588
+ switch ( action . type ) {
2589
+ case input . ActionType . KEY_DOWN : {
2590
+ // If this action is a keydown for a non-modifier key, the next action
2591
+ // must be a keyup for the same key, otherwise it cannot be translated
2592
+ // to the legacy action API.
2593
+ if ( ! MODIFIER_KEYS . has ( action . value ) ) {
2594
+ const np1 = device . actions [ i + 1 ] ;
2595
+ if ( ! np1
2596
+ || np1 . type !== input . ActionType . KEY_UP
2597
+ || np1 . value !== action . value ) {
2598
+ throw new error . UnsupportedOperationError (
2599
+ 'Unable to translate sequence to legacy API: keydown for '
2600
+ + `<${ action . value } > must be followed by a keyup for the `
2601
+ + 'same key' ) ;
2602
+ }
2603
+ }
2604
+ commands . push (
2605
+ new command . Command ( command . Name . LEGACY_ACTION_SEND_KEYS )
2606
+ . setParameter ( 'value' , [ action . value ] ) ) ;
2607
+ break ;
2608
+ }
2609
+ case input . ActionType . KEY_UP : {
2610
+ // The legacy API always treats sendKeys for a non-modifier to be a
2611
+ // keydown/up pair. For modifiers, the sendKeys toggles the key state,
2612
+ // so we can omit any keyup actions for non-modifier keys.
2613
+ if ( MODIFIER_KEYS . has ( action . value ) ) {
2614
+ commands . push (
2615
+ new command . Command ( command . Name . LEGACY_ACTION_SEND_KEYS )
2616
+ . setParameter ( 'value' , [ action . value ] ) ) ;
2617
+ }
2618
+ break ;
2619
+ }
2620
+ case input . ActionType . POINTER_DOWN :
2621
+ commands . push (
2622
+ new command . Command ( command . Name . LEGACY_ACTION_MOUSE_DOWN )
2623
+ . setParameter ( 'button' , action . button ) ) ;
2624
+ break ;
2625
+ case input . ActionType . POINTER_UP :
2626
+ commands . push (
2627
+ new command . Command ( command . Name . LEGACY_ACTION_MOUSE_UP )
2628
+ . setParameter ( 'button' , action . button ) ) ;
2629
+ break ;
2630
+ case input . ActionType . POINTER_MOVE : {
2631
+ let cmd = new command . Command ( command . Name . LEGACY_ACTION_MOUSE_MOVE )
2632
+ . setParameter ( 'xoffset' , action . x )
2633
+ . setParameter ( 'yoffset' , action . y ) ;
2634
+ if ( WebElement . isId ( action . origin ) ) {
2635
+ cmd . setParameter ( 'element' , WebElement . extractId ( action . origin ) ) ;
2636
+ }
2637
+ commands . push ( cmd ) ;
2638
+ break ;
2639
+ }
2640
+ default :
2641
+ throw new error . UnsupportedOperationError (
2642
+ 'Unable to translate action to legacy API: '
2643
+ + JSON . stringify ( action ) ) ;
2644
+ }
2645
+ }
2527
2646
}
2647
+ return commands ;
2528
2648
}
2529
2649
2530
2650
0 commit comments