Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/javascript/selenium-webdriver/test/lib/input_test.js
2885 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
'use strict'
19
20
const assert = require('node:assert')
21
const command = require('selenium-webdriver/lib/command')
22
const error = require('selenium-webdriver/lib/error')
23
const input = require('selenium-webdriver/lib/input')
24
const { WebElement } = require('selenium-webdriver/lib/webdriver')
25
26
describe('input.Actions', function () {
27
class StubExecutor {
28
constructor(...responses) {
29
this.responses = responses
30
this.commands = []
31
}
32
33
execute(command) {
34
const name = command.getName()
35
const parameters = command.getParameters()
36
this.commands.push({ name, parameters })
37
return this.responses.shift() || Promise.reject(new Error('unexpected command: ' + command.getName()))
38
}
39
}
40
41
describe('perform()', function () {
42
it('omits idle devices', async function () {
43
let executor = new StubExecutor(Promise.resolve(), Promise.resolve(), Promise.resolve(), Promise.resolve())
44
45
await new input.Actions(executor).perform()
46
assert.deepStrictEqual(executor.commands, [])
47
48
await new input.Actions(executor).pause().perform()
49
assert.deepStrictEqual(executor.commands, [])
50
51
await new input.Actions(executor).pause(1).perform()
52
assert.deepStrictEqual(executor.commands, [
53
{
54
name: command.Name.ACTIONS,
55
parameters: {
56
actions: [
57
{
58
id: 'default keyboard',
59
type: 'key',
60
actions: [{ type: 'pause', duration: 1 }],
61
},
62
{
63
id: 'default mouse',
64
type: 'pointer',
65
parameters: { pointerType: 'mouse' },
66
actions: [{ type: 'pause', duration: 1 }],
67
},
68
{
69
id: 'default wheel',
70
type: 'wheel',
71
actions: [{ type: 'pause', duration: 1 }],
72
},
73
],
74
},
75
},
76
])
77
78
executor.commands.length = 0
79
let actions = new input.Actions(executor)
80
await actions.pause(1, actions.keyboard()).perform()
81
assert.deepStrictEqual(executor.commands, [
82
{
83
name: command.Name.ACTIONS,
84
parameters: {
85
actions: [
86
{
87
id: 'default keyboard',
88
type: 'key',
89
actions: [{ type: 'pause', duration: 1 }],
90
},
91
],
92
},
93
},
94
])
95
})
96
97
it('can be called multiple times', async function () {
98
const executor = new StubExecutor(Promise.resolve(), Promise.resolve())
99
const actions = new input.Actions(executor).keyDown(input.Key.SHIFT)
100
101
const expected = {
102
name: command.Name.ACTIONS,
103
parameters: {
104
actions: [
105
{
106
id: 'default keyboard',
107
type: 'key',
108
actions: [{ type: 'keyDown', value: input.Key.SHIFT }],
109
},
110
],
111
},
112
}
113
114
await actions.perform()
115
assert.deepStrictEqual(executor.commands, [expected])
116
117
await actions.perform()
118
assert.deepStrictEqual(executor.commands, [expected, expected])
119
})
120
})
121
122
describe('pause()', function () {
123
it('defaults to all devices', async function () {
124
const executor = new StubExecutor(Promise.resolve())
125
126
await new input.Actions(executor).pause(3).perform()
127
128
assert.deepStrictEqual(executor.commands, [
129
{
130
name: command.Name.ACTIONS,
131
parameters: {
132
actions: [
133
{
134
id: 'default keyboard',
135
type: 'key',
136
actions: [{ type: 'pause', duration: 3 }],
137
},
138
{
139
id: 'default mouse',
140
type: 'pointer',
141
parameters: { pointerType: 'mouse' },
142
actions: [{ type: 'pause', duration: 3 }],
143
},
144
{
145
id: 'default wheel',
146
type: 'wheel',
147
actions: [
148
{
149
duration: 3,
150
type: 'pause',
151
},
152
],
153
},
154
],
155
},
156
},
157
])
158
})
159
160
it('duration defaults to 0', async function () {
161
const executor = new StubExecutor(Promise.resolve())
162
163
await new input.Actions(executor).pause().pause(3).perform()
164
165
assert.deepStrictEqual(executor.commands, [
166
{
167
name: command.Name.ACTIONS,
168
parameters: {
169
actions: [
170
{
171
id: 'default keyboard',
172
type: 'key',
173
actions: [
174
{ type: 'pause', duration: 0 },
175
{ type: 'pause', duration: 3 },
176
],
177
},
178
{
179
id: 'default mouse',
180
type: 'pointer',
181
parameters: { pointerType: 'mouse' },
182
actions: [
183
{ type: 'pause', duration: 0 },
184
{ type: 'pause', duration: 3 },
185
],
186
},
187
{
188
id: 'default wheel',
189
type: 'wheel',
190
actions: [
191
{ type: 'pause', duration: 0 },
192
{ type: 'pause', duration: 3 },
193
],
194
},
195
],
196
},
197
},
198
])
199
})
200
201
it('single device w/ synchronization', async function () {
202
const executor = new StubExecutor(Promise.resolve())
203
const actions = new input.Actions(executor)
204
205
await actions.pause(100, actions.keyboard()).pause(100, actions.mouse()).perform()
206
207
assert.deepStrictEqual(executor.commands, [
208
{
209
name: command.Name.ACTIONS,
210
parameters: {
211
actions: [
212
{
213
id: 'default keyboard',
214
type: 'key',
215
actions: [
216
{ type: 'pause', duration: 100 },
217
{ type: 'pause', duration: 0 },
218
],
219
},
220
{
221
id: 'default mouse',
222
type: 'pointer',
223
parameters: { pointerType: 'mouse' },
224
actions: [
225
{ type: 'pause', duration: 0 },
226
{ type: 'pause', duration: 100 },
227
],
228
},
229
],
230
},
231
},
232
])
233
})
234
235
it('single device w/o synchronization', async function () {
236
const executor = new StubExecutor(Promise.resolve())
237
const actions = new input.Actions(executor, { async: true })
238
239
await actions.pause(100, actions.keyboard()).pause(100, actions.mouse()).perform()
240
241
assert.deepStrictEqual(executor.commands, [
242
{
243
name: command.Name.ACTIONS,
244
parameters: {
245
actions: [
246
{
247
id: 'default keyboard',
248
type: 'key',
249
actions: [{ type: 'pause', duration: 100 }],
250
},
251
{
252
id: 'default mouse',
253
type: 'pointer',
254
parameters: { pointerType: 'mouse' },
255
actions: [{ type: 'pause', duration: 100 }],
256
},
257
],
258
},
259
},
260
])
261
})
262
263
it('pause a single device multiple times by specifying it multiple times', async function () {
264
const executor = new StubExecutor(Promise.resolve())
265
const actions = new input.Actions(executor)
266
267
await actions.pause(100, actions.keyboard(), actions.keyboard()).perform()
268
269
assert.deepStrictEqual(executor.commands, [
270
{
271
name: command.Name.ACTIONS,
272
parameters: {
273
actions: [
274
{
275
id: 'default keyboard',
276
type: 'key',
277
actions: [
278
{ type: 'pause', duration: 100 },
279
{ type: 'pause', duration: 100 },
280
],
281
},
282
],
283
},
284
},
285
])
286
})
287
})
288
289
describe('keyDown()', function () {
290
it('sends normalized code point', async function () {
291
let executor = new StubExecutor(Promise.resolve())
292
293
await new input.Actions(executor).keyDown('\u0041\u030a').perform()
294
assert.deepStrictEqual(executor.commands, [
295
{
296
name: command.Name.ACTIONS,
297
parameters: {
298
actions: [
299
{
300
id: 'default keyboard',
301
type: 'key',
302
actions: [{ type: 'keyDown', value: '\u00c5' }],
303
},
304
],
305
},
306
},
307
])
308
})
309
310
it('rejects keys that are not a single code point', function () {
311
const executor = new StubExecutor(Promise.resolve())
312
const actions = new input.Actions(executor)
313
assert.throws(() => actions.keyDown('\u1E9B\u0323'), error.InvalidArgumentError)
314
})
315
})
316
317
describe('keyUp()', function () {
318
it('sends normalized code point', async function () {
319
let executor = new StubExecutor(Promise.resolve())
320
321
await new input.Actions(executor).keyUp('\u0041\u030a').perform()
322
assert.deepStrictEqual(executor.commands, [
323
{
324
name: command.Name.ACTIONS,
325
parameters: {
326
actions: [
327
{
328
id: 'default keyboard',
329
type: 'key',
330
actions: [{ type: 'keyUp', value: '\u00c5' }],
331
},
332
],
333
},
334
},
335
])
336
})
337
338
it('rejects keys that are not a single code point', function () {
339
const executor = new StubExecutor(Promise.resolve())
340
const actions = new input.Actions(executor)
341
assert.throws(() => actions.keyUp('\u1E9B\u0323'), error.InvalidArgumentError)
342
})
343
})
344
345
describe('sendKeys()', function () {
346
it('sends down/up for single key', async function () {
347
const executor = new StubExecutor(Promise.resolve())
348
const actions = new input.Actions(executor)
349
350
await actions.sendKeys('a').perform()
351
assert.deepStrictEqual(executor.commands, [
352
{
353
name: command.Name.ACTIONS,
354
parameters: {
355
actions: [
356
{
357
id: 'default keyboard',
358
type: 'key',
359
actions: [
360
{ type: 'keyDown', value: 'a' },
361
{ type: 'keyUp', value: 'a' },
362
],
363
},
364
],
365
},
366
},
367
])
368
})
369
370
it('sends down/up for vararg keys', async function () {
371
const executor = new StubExecutor(Promise.resolve())
372
const actions = new input.Actions(executor)
373
374
await actions.sendKeys('a', 'b').perform()
375
assert.deepStrictEqual(executor.commands, [
376
{
377
name: command.Name.ACTIONS,
378
parameters: {
379
actions: [
380
{
381
id: 'default keyboard',
382
type: 'key',
383
actions: [
384
{ type: 'keyDown', value: 'a' },
385
{ type: 'keyUp', value: 'a' },
386
{ type: 'keyDown', value: 'b' },
387
{ type: 'keyUp', value: 'b' },
388
],
389
},
390
],
391
},
392
},
393
])
394
})
395
396
it('sends down/up for multichar strings in varargs', async function () {
397
const executor = new StubExecutor(Promise.resolve())
398
const actions = new input.Actions(executor)
399
400
await actions.sendKeys('a', 'bc', 'd').perform()
401
assert.deepStrictEqual(executor.commands, [
402
{
403
name: command.Name.ACTIONS,
404
parameters: {
405
actions: [
406
{
407
id: 'default keyboard',
408
type: 'key',
409
actions: [
410
{ type: 'keyDown', value: 'a' },
411
{ type: 'keyUp', value: 'a' },
412
{ type: 'keyDown', value: 'b' },
413
{ type: 'keyUp', value: 'b' },
414
{ type: 'keyDown', value: 'c' },
415
{ type: 'keyUp', value: 'c' },
416
{ type: 'keyDown', value: 'd' },
417
{ type: 'keyUp', value: 'd' },
418
],
419
},
420
],
421
},
422
},
423
])
424
})
425
426
it('synchronizes with other devices', async function () {
427
const executor = new StubExecutor(Promise.resolve())
428
const actions = new input.Actions(executor)
429
430
await actions.sendKeys('ab').pause(100, actions.mouse()).perform()
431
assert.deepStrictEqual(executor.commands, [
432
{
433
name: command.Name.ACTIONS,
434
parameters: {
435
actions: [
436
{
437
id: 'default keyboard',
438
type: 'key',
439
actions: [
440
{ type: 'keyDown', value: 'a' },
441
{ type: 'keyUp', value: 'a' },
442
{ type: 'keyDown', value: 'b' },
443
{ type: 'keyUp', value: 'b' },
444
{ type: 'pause', duration: 0 },
445
],
446
},
447
{
448
id: 'default mouse',
449
type: 'pointer',
450
parameters: { pointerType: 'mouse' },
451
actions: [
452
{ type: 'pause', duration: 0 },
453
{ type: 'pause', duration: 0 },
454
{ type: 'pause', duration: 0 },
455
{ type: 'pause', duration: 0 },
456
{ type: 'pause', duration: 100 },
457
],
458
},
459
],
460
},
461
},
462
])
463
})
464
465
it('without device synchronization', async function () {
466
const executor = new StubExecutor(Promise.resolve())
467
const actions = new input.Actions(executor, { async: true })
468
469
await actions.sendKeys('ab').pause(100, actions.mouse()).perform()
470
assert.deepStrictEqual(executor.commands, [
471
{
472
name: command.Name.ACTIONS,
473
parameters: {
474
actions: [
475
{
476
id: 'default keyboard',
477
type: 'key',
478
actions: [
479
{ type: 'keyDown', value: 'a' },
480
{ type: 'keyUp', value: 'a' },
481
{ type: 'keyDown', value: 'b' },
482
{ type: 'keyUp', value: 'b' },
483
],
484
},
485
{
486
id: 'default mouse',
487
type: 'pointer',
488
parameters: { pointerType: 'mouse' },
489
actions: [{ type: 'pause', duration: 100 }],
490
},
491
],
492
},
493
},
494
])
495
})
496
497
it('string length > 500', async function () {
498
const executor = new StubExecutor(Promise.resolve())
499
const actions = new input.Actions(executor, { async: true })
500
let str = ''
501
for (let i = 0; i < 501; i++) {
502
str += i
503
}
504
const executionResult = await actions
505
.sendKeys(str)
506
.perform()
507
.then(() => true)
508
.catch(() => false)
509
assert.strictEqual(executionResult, true)
510
})
511
})
512
513
describe('click()', function () {
514
it('clicks immediately if no element provided', async function () {
515
const executor = new StubExecutor(Promise.resolve())
516
const actions = new input.Actions(executor)
517
518
await actions.click().perform()
519
assert.deepStrictEqual(executor.commands, [
520
{
521
name: command.Name.ACTIONS,
522
parameters: {
523
actions: [
524
{
525
id: 'default mouse',
526
type: 'pointer',
527
parameters: { pointerType: 'mouse' },
528
actions: [
529
{
530
type: 'pointerDown',
531
button: input.Button.LEFT,
532
altitudeAngle: 0,
533
azimuthAngle: 0,
534
width: 0,
535
height: 0,
536
pressure: 0,
537
tangentialPressure: 0,
538
tiltX: 0,
539
tiltY: 0,
540
twist: 0,
541
},
542
{ type: 'pointerUp', button: input.Button.LEFT },
543
],
544
},
545
],
546
},
547
},
548
])
549
})
550
551
it('moves to target element before clicking', async function () {
552
const executor = new StubExecutor(Promise.resolve())
553
const actions = new input.Actions(executor)
554
555
const fakeElement = {}
556
557
await actions.click(fakeElement).perform()
558
assert.deepStrictEqual(executor.commands, [
559
{
560
name: command.Name.ACTIONS,
561
parameters: {
562
actions: [
563
{
564
id: 'default mouse',
565
type: 'pointer',
566
parameters: { pointerType: 'mouse' },
567
actions: [
568
{
569
type: 'pointerMove',
570
origin: fakeElement,
571
duration: 100,
572
x: 0,
573
y: 0,
574
altitudeAngle: 0,
575
azimuthAngle: 0,
576
width: 0,
577
height: 0,
578
pressure: 0,
579
tangentialPressure: 0,
580
tiltX: 0,
581
tiltY: 0,
582
twist: 0,
583
},
584
{
585
type: 'pointerDown',
586
button: input.Button.LEFT,
587
altitudeAngle: 0,
588
azimuthAngle: 0,
589
width: 0,
590
height: 0,
591
pressure: 0,
592
tangentialPressure: 0,
593
tiltX: 0,
594
tiltY: 0,
595
twist: 0,
596
},
597
{ type: 'pointerUp', button: input.Button.LEFT },
598
],
599
},
600
],
601
},
602
},
603
])
604
})
605
606
it('synchronizes with other devices', async function () {
607
const executor = new StubExecutor(Promise.resolve())
608
const actions = new input.Actions(executor)
609
610
const fakeElement = {}
611
612
await actions.click(fakeElement).sendKeys('a').perform()
613
assert.deepStrictEqual(executor.commands, [
614
{
615
name: command.Name.ACTIONS,
616
parameters: {
617
actions: [
618
{
619
id: 'default keyboard',
620
type: 'key',
621
actions: [
622
{ type: 'pause', duration: 0 },
623
{ type: 'pause', duration: 0 },
624
{ type: 'pause', duration: 0 },
625
{ type: 'keyDown', value: 'a' },
626
{ type: 'keyUp', value: 'a' },
627
],
628
},
629
{
630
id: 'default mouse',
631
type: 'pointer',
632
parameters: { pointerType: 'mouse' },
633
actions: [
634
{
635
type: 'pointerMove',
636
origin: fakeElement,
637
duration: 100,
638
x: 0,
639
y: 0,
640
altitudeAngle: 0,
641
azimuthAngle: 0,
642
width: 0,
643
height: 0,
644
pressure: 0,
645
tangentialPressure: 0,
646
tiltX: 0,
647
tiltY: 0,
648
twist: 0,
649
},
650
{
651
type: 'pointerDown',
652
button: input.Button.LEFT,
653
altitudeAngle: 0,
654
azimuthAngle: 0,
655
width: 0,
656
height: 0,
657
pressure: 0,
658
tangentialPressure: 0,
659
tiltX: 0,
660
tiltY: 0,
661
twist: 0,
662
},
663
{ type: 'pointerUp', button: input.Button.LEFT },
664
{ type: 'pause', duration: 0 },
665
{ type: 'pause', duration: 0 },
666
],
667
},
668
],
669
},
670
},
671
])
672
})
673
})
674
675
describe('dragAndDrop', function () {
676
it('dragAndDrop(fromEl, toEl)', async function () {
677
const executor = new StubExecutor(Promise.resolve())
678
const actions = new input.Actions(executor)
679
const e1 = new WebElement(null, 'abc123')
680
const e2 = new WebElement(null, 'def456')
681
682
await actions.dragAndDrop(e1, e2).perform()
683
684
assert.deepStrictEqual(executor.commands, [
685
{
686
name: command.Name.ACTIONS,
687
parameters: {
688
actions: [
689
{
690
id: 'default mouse',
691
type: 'pointer',
692
parameters: { pointerType: 'mouse' },
693
actions: [
694
{
695
type: 'pointerMove',
696
duration: 100,
697
origin: e1,
698
x: 0,
699
y: 0,
700
altitudeAngle: 0,
701
azimuthAngle: 0,
702
width: 0,
703
height: 0,
704
pressure: 0,
705
tangentialPressure: 0,
706
tiltX: 0,
707
tiltY: 0,
708
twist: 0,
709
},
710
{
711
type: 'pointerDown',
712
button: input.Button.LEFT,
713
altitudeAngle: 0,
714
azimuthAngle: 0,
715
width: 0,
716
height: 0,
717
pressure: 0,
718
tangentialPressure: 0,
719
tiltX: 0,
720
tiltY: 0,
721
twist: 0,
722
},
723
{
724
type: 'pointerMove',
725
duration: 100,
726
origin: e2,
727
x: 0,
728
y: 0,
729
altitudeAngle: 0,
730
azimuthAngle: 0,
731
width: 0,
732
height: 0,
733
pressure: 0,
734
tangentialPressure: 0,
735
tiltX: 0,
736
tiltY: 0,
737
twist: 0,
738
},
739
{ type: 'pointerUp', button: input.Button.LEFT },
740
],
741
},
742
],
743
},
744
},
745
])
746
})
747
748
it('dragAndDrop(el, offset)', async function () {
749
const executor = new StubExecutor(Promise.resolve())
750
const actions = new input.Actions(executor)
751
const e1 = new WebElement(null, 'abc123')
752
753
await actions.dragAndDrop(e1, { x: 30, y: 40 }).perform()
754
755
assert.deepStrictEqual(executor.commands, [
756
{
757
name: command.Name.ACTIONS,
758
parameters: {
759
actions: [
760
{
761
id: 'default mouse',
762
type: 'pointer',
763
parameters: { pointerType: 'mouse' },
764
actions: [
765
{
766
type: 'pointerMove',
767
duration: 100,
768
origin: e1,
769
x: 0,
770
y: 0,
771
altitudeAngle: 0,
772
azimuthAngle: 0,
773
width: 0,
774
height: 0,
775
pressure: 0,
776
tangentialPressure: 0,
777
tiltX: 0,
778
tiltY: 0,
779
twist: 0,
780
},
781
{
782
type: 'pointerDown',
783
button: input.Button.LEFT,
784
altitudeAngle: 0,
785
azimuthAngle: 0,
786
width: 0,
787
height: 0,
788
pressure: 0,
789
tangentialPressure: 0,
790
tiltX: 0,
791
tiltY: 0,
792
twist: 0,
793
},
794
{
795
type: 'pointerMove',
796
duration: 100,
797
origin: input.Origin.POINTER,
798
x: 30,
799
y: 40,
800
altitudeAngle: 0,
801
azimuthAngle: 0,
802
width: 0,
803
height: 0,
804
pressure: 0,
805
tangentialPressure: 0,
806
tiltX: 0,
807
tiltY: 0,
808
twist: 0,
809
},
810
{ type: 'pointerUp', button: input.Button.LEFT },
811
],
812
},
813
],
814
},
815
},
816
])
817
})
818
819
it('throws if target is invalid', async function () {
820
const executor = new StubExecutor(Promise.resolve())
821
const actions = new input.Actions(executor)
822
const e = new WebElement(null, 'abc123')
823
824
assert.throws(() => actions.dragAndDrop(e), error.InvalidArgumentError)
825
assert.throws(() => actions.dragAndDrop(e, null), error.InvalidArgumentError)
826
assert.throws(() => actions.dragAndDrop(e, {}), error.InvalidArgumentError)
827
assert.throws(() => actions.dragAndDrop(e, { x: 0 }), error.InvalidArgumentError)
828
assert.throws(() => actions.dragAndDrop(e, { y: 0 }), error.InvalidArgumentError)
829
assert.throws(() => actions.dragAndDrop(e, { x: 0, y: 'a' }), error.InvalidArgumentError)
830
assert.throws(() => actions.dragAndDrop(e, { x: 'a', y: 0 }), error.InvalidArgumentError)
831
})
832
})
833
})
834
835