19
19
20
20
using System ;
21
21
using System . Collections . Generic ;
22
+ using System . Diagnostics . CodeAnalysis ;
23
+
24
+ #nullable enable
22
25
23
26
namespace OpenQA . Selenium . Interactions
24
27
{
@@ -29,9 +32,9 @@ public class Actions : IAction
29
32
{
30
33
private readonly TimeSpan duration ;
31
34
private ActionBuilder actionBuilder = new ActionBuilder ( ) ;
32
- private PointerInputDevice activePointer ;
33
- private KeyInputDevice activeKeyboard ;
34
- private WheelInputDevice activeWheel ;
35
+ private PointerInputDevice ? activePointer ;
36
+ private KeyInputDevice ? activeKeyboard ;
37
+ private WheelInputDevice ? activeWheel ;
35
38
36
39
/// <summary>
37
40
/// Initializes a new instance of the <see cref="Actions"/> class.
@@ -51,14 +54,10 @@ public Actions(IWebDriver driver)
51
54
/// <exception cref="ArgumentException">If <paramref name="driver"/> does not implement <see cref="IActionExecutor"/>.</exception>
52
55
public Actions ( IWebDriver driver , TimeSpan duration )
53
56
{
54
- IActionExecutor actionExecutor = GetDriverAs < IActionExecutor > ( driver ) ;
55
- if ( actionExecutor == null )
56
- {
57
- throw new ArgumentException ( "The IWebDriver object must implement or wrap a driver that implements IActionExecutor." , nameof ( driver ) ) ;
58
- }
57
+ IActionExecutor actionExecutor = GetDriverAs < IActionExecutor > ( driver )
58
+ ?? throw new ArgumentException ( "The IWebDriver object must implement or wrap a driver that implements IActionExecutor." , nameof ( driver ) ) ;
59
59
60
60
this . ActionExecutor = actionExecutor ;
61
-
62
61
this . duration = duration ;
63
62
}
64
63
@@ -74,9 +73,10 @@ public Actions(IWebDriver driver, TimeSpan duration)
74
73
/// <param name="name">The name of the pointer device to set as active.</param>
75
74
/// <returns>A self-reference to this Actions class.</returns>
76
75
/// <exception cref="InvalidOperationException">If a device with this name exists but is not a pointer.</exception>
76
+ [ MemberNotNull ( nameof ( activePointer ) ) ]
77
77
public Actions SetActivePointer ( PointerKind kind , string name )
78
78
{
79
- InputDevice device = FindDeviceById ( name ) ;
79
+ InputDevice ? device = FindDeviceById ( name ) ;
80
80
81
81
this . activePointer = device switch
82
82
{
@@ -94,9 +94,10 @@ public Actions SetActivePointer(PointerKind kind, string name)
94
94
/// <param name="name">The name of the keyboard device to set as active.</param>
95
95
/// <returns>A self-reference to this Actions class.</returns>
96
96
/// <exception cref="InvalidOperationException">If a device with this name exists but is not a keyboard.</exception>
97
+ [ MemberNotNull ( nameof ( activeKeyboard ) ) ]
97
98
public Actions SetActiveKeyboard ( string name )
98
99
{
99
- InputDevice device = FindDeviceById ( name ) ;
100
+ InputDevice ? device = FindDeviceById ( name ) ;
100
101
101
102
this . activeKeyboard = device switch
102
103
{
@@ -114,9 +115,10 @@ public Actions SetActiveKeyboard(string name)
114
115
/// <param name="name">The name of the wheel device to set as active.</param>
115
116
/// <returns>A self-reference to this Actions class.</returns>
116
117
/// <exception cref="InvalidOperationException">If a device with this name exists but is not a wheel.</exception>
118
+ [ MemberNotNull ( nameof ( activeWheel ) ) ]
117
119
public Actions SetActiveWheel ( string name )
118
120
{
119
- InputDevice device = FindDeviceById ( name ) ;
121
+ InputDevice ? device = FindDeviceById ( name ) ;
120
122
121
123
this . activeWheel = device switch
122
124
{
@@ -128,7 +130,7 @@ public Actions SetActiveWheel(string name)
128
130
return this ;
129
131
}
130
132
131
- private InputDevice FindDeviceById ( string name )
133
+ private InputDevice ? FindDeviceById ( string ? name )
132
134
{
133
135
foreach ( var sequence in this . actionBuilder . ToActionSequenceList ( ) )
134
136
{
@@ -211,14 +213,14 @@ public Actions KeyDown(string theKey)
211
213
/// of <see cref="Keys.Shift"/>, <see cref="Keys.Control"/>, <see cref="Keys.Alt"/>,
212
214
/// <see cref="Keys.Meta"/>, <see cref="Keys.Command"/>,<see cref="Keys.LeftAlt"/>,
213
215
/// <see cref="Keys.LeftControl"/>,<see cref="Keys.LeftShift"/>.</exception>
214
- public Actions KeyDown ( IWebElement element , string theKey )
216
+ public Actions KeyDown ( IWebElement ? element , string theKey )
215
217
{
216
218
if ( string . IsNullOrEmpty ( theKey ) )
217
219
{
218
220
throw new ArgumentException ( "The key value must not be null or empty" , nameof ( theKey ) ) ;
219
221
}
220
222
221
- ILocatable target = GetLocatableFromElement ( element ) ;
223
+ ILocatable ? target = GetLocatableFromElement ( element ) ;
222
224
if ( element != null )
223
225
{
224
226
this . actionBuilder . AddAction ( this . GetActivePointer ( ) . CreatePointerMove ( element , 0 , 0 , duration ) ) ;
@@ -255,14 +257,14 @@ public Actions KeyUp(string theKey)
255
257
/// of <see cref="Keys.Shift"/>, <see cref="Keys.Control"/>, <see cref="Keys.Alt"/>,
256
258
/// <see cref="Keys.Meta"/>, <see cref="Keys.Command"/>,<see cref="Keys.LeftAlt"/>,
257
259
/// <see cref="Keys.LeftControl"/>,<see cref="Keys.LeftShift"/>.</exception>
258
- public Actions KeyUp ( IWebElement element , string theKey )
260
+ public Actions KeyUp ( IWebElement ? element , string theKey )
259
261
{
260
262
if ( string . IsNullOrEmpty ( theKey ) )
261
263
{
262
264
throw new ArgumentException ( "The key value must not be null or empty" , nameof ( theKey ) ) ;
263
265
}
264
266
265
- ILocatable target = GetLocatableFromElement ( element ) ;
267
+ ILocatable ? target = GetLocatableFromElement ( element ) ;
266
268
if ( element != null )
267
269
{
268
270
this . actionBuilder . AddAction ( this . GetActivePointer ( ) . CreatePointerMove ( element , 0 , 0 , duration ) ) ;
@@ -279,6 +281,7 @@ public Actions KeyUp(IWebElement element, string theKey)
279
281
/// </summary>
280
282
/// <param name="keysToSend">The keystrokes to send to the browser.</param>
281
283
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
284
+ /// <exception cref="ArgumentException">If <paramref name="keysToSend"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
282
285
public Actions SendKeys ( string keysToSend )
283
286
{
284
287
return this . SendKeys ( null , keysToSend ) ;
@@ -290,14 +293,15 @@ public Actions SendKeys(string keysToSend)
290
293
/// <param name="element">The element to which to send the keystrokes.</param>
291
294
/// <param name="keysToSend">The keystrokes to send to the browser.</param>
292
295
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
293
- public Actions SendKeys ( IWebElement element , string keysToSend )
296
+ /// <exception cref="ArgumentException">If <paramref name="keysToSend"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
297
+ public Actions SendKeys ( IWebElement ? element , string keysToSend )
294
298
{
295
299
if ( string . IsNullOrEmpty ( keysToSend ) )
296
300
{
297
301
throw new ArgumentException ( "The key value must not be null or empty" , nameof ( keysToSend ) ) ;
298
302
}
299
303
300
- ILocatable target = GetLocatableFromElement ( element ) ;
304
+ ILocatable ? target = GetLocatableFromElement ( element ) ;
301
305
if ( element != null )
302
306
{
303
307
this . actionBuilder . AddAction ( this . GetActivePointer ( ) . CreatePointerMove ( element , 0 , 0 , duration ) ) ;
@@ -319,6 +323,7 @@ public Actions SendKeys(IWebElement element, string keysToSend)
319
323
/// </summary>
320
324
/// <param name="onElement">The element on which to click and hold.</param>
321
325
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
326
+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
322
327
public Actions ClickAndHold ( IWebElement onElement )
323
328
{
324
329
this . MoveToElement ( onElement ) . ClickAndHold ( ) ;
@@ -340,6 +345,7 @@ public Actions ClickAndHold()
340
345
/// </summary>
341
346
/// <param name="onElement">The element on which to release the button.</param>
342
347
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
348
+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
343
349
public Actions Release ( IWebElement onElement )
344
350
{
345
351
this . MoveToElement ( onElement ) . Release ( ) ;
@@ -361,6 +367,7 @@ public Actions Release()
361
367
/// </summary>
362
368
/// <param name="onElement">The element on which to click.</param>
363
369
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
370
+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
364
371
public Actions Click ( IWebElement onElement )
365
372
{
366
373
this . MoveToElement ( onElement ) . Click ( ) ;
@@ -383,6 +390,7 @@ public Actions Click()
383
390
/// </summary>
384
391
/// <param name="onElement">The element on which to double-click.</param>
385
392
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
393
+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
386
394
public Actions DoubleClick ( IWebElement onElement )
387
395
{
388
396
this . MoveToElement ( onElement ) . DoubleClick ( ) ;
@@ -407,6 +415,7 @@ public Actions DoubleClick()
407
415
/// </summary>
408
416
/// <param name="toElement">The element to which to move the mouse.</param>
409
417
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
418
+ /// <exception cref="ArgumentNullException">If <paramref name="toElement"/> is null.</exception>
410
419
public Actions MoveToElement ( IWebElement toElement )
411
420
{
412
421
if ( toElement == null )
@@ -460,6 +469,7 @@ public Actions MoveToLocation(int offsetX, int offsetY)
460
469
/// </summary>
461
470
/// <param name="onElement">The element on which to right-click.</param>
462
471
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
472
+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
463
473
public Actions ContextClick ( IWebElement onElement )
464
474
{
465
475
this . MoveToElement ( onElement ) . ContextClick ( ) ;
@@ -483,6 +493,7 @@ public Actions ContextClick()
483
493
/// <param name="source">The element on which the drag operation is started.</param>
484
494
/// <param name="target">The element on which the drop is performed.</param>
485
495
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
496
+ /// <exception cref="ArgumentNullException">If <paramref name="source"/> or <paramref name="target"/> are null.</exception>
486
497
public Actions DragAndDrop ( IWebElement source , IWebElement target )
487
498
{
488
499
this . ClickAndHold ( source ) . MoveToElement ( target ) . Release ( target ) ;
@@ -496,6 +507,7 @@ public Actions DragAndDrop(IWebElement source, IWebElement target)
496
507
/// <param name="offsetX">The horizontal offset to which to move the mouse.</param>
497
508
/// <param name="offsetY">The vertical offset to which to move the mouse.</param>
498
509
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
510
+ /// <exception cref="ArgumentNullException">If <paramref name="source"/> is null.</exception>
499
511
public Actions DragAndDropToOffset ( IWebElement source , int offsetX , int offsetY )
500
512
{
501
513
this . ClickAndHold ( source ) . MoveByOffset ( offsetX , offsetY ) . Release ( ) ;
@@ -507,6 +519,7 @@ public Actions DragAndDropToOffset(IWebElement source, int offsetX, int offsetY)
507
519
/// </summary>
508
520
/// <param name="element">Which element to scroll into the viewport.</param>
509
521
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
522
+ /// <exception cref="ArgumentNullException">If <paramref name="element"/> is null.</exception>
510
523
public Actions ScrollToElement ( IWebElement element )
511
524
{
512
525
this . actionBuilder . AddAction ( this . GetActiveWheel ( ) . CreateWheelScroll ( element , 0 , 0 , 0 , 0 , duration ) ) ;
@@ -540,8 +553,15 @@ public Actions ScrollByAmount(int deltaX, int deltaY)
540
553
/// <param name="deltaY">Distance along Y axis to scroll using the wheel. A negative value scrolls up.</param>
541
554
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
542
555
/// <exception cref="MoveTargetOutOfBoundsException">If the origin with offset is outside the viewport.</exception>
556
+ /// <exception cref="ArgumentNullException">If <paramref name="scrollOrigin"/> is null.</exception>
557
+ /// <exception cref="ArgumentException">If both or either of Viewport and Element are set.</exception>
543
558
public Actions ScrollFromOrigin ( WheelInputDevice . ScrollOrigin scrollOrigin , int deltaX , int deltaY )
544
559
{
560
+ if ( scrollOrigin is null )
561
+ {
562
+ throw new ArgumentNullException ( nameof ( scrollOrigin ) ) ;
563
+ }
564
+
545
565
if ( scrollOrigin . Viewport && scrollOrigin . Element != null )
546
566
{
547
567
throw new ArgumentException ( "viewport can not be true if an element is defined." , nameof ( scrollOrigin ) ) ;
@@ -554,7 +574,7 @@ public Actions ScrollFromOrigin(WheelInputDevice.ScrollOrigin scrollOrigin, int
554
574
}
555
575
else
556
576
{
557
- this . actionBuilder . AddAction ( this . GetActiveWheel ( ) . CreateWheelScroll ( scrollOrigin . Element ,
577
+ this . actionBuilder . AddAction ( this . GetActiveWheel ( ) . CreateWheelScroll ( scrollOrigin . Element ! ,
558
578
scrollOrigin . XOffset , scrollOrigin . YOffset , deltaX , deltaY , duration ) ) ;
559
579
}
560
580
@@ -566,6 +586,7 @@ public Actions ScrollFromOrigin(WheelInputDevice.ScrollOrigin scrollOrigin, int
566
586
/// </summary>
567
587
/// <param name="duration">How long to pause the action chain.</param>
568
588
/// <returns>A self-reference to this <see cref="Actions"/>.</returns>
589
+ /// <exception cref="ArgumentException">If <paramref name="duration"/> is negative.</exception>
569
590
public Actions Pause ( TimeSpan duration )
570
591
{
571
592
this . actionBuilder . AddAction ( new PauseInteraction ( this . GetActivePointer ( ) , duration ) ) ;
@@ -603,15 +624,16 @@ public void Reset()
603
624
/// </summary>
604
625
/// <param name="element">The <see cref="IWebElement"/> to get the location of.</param>
605
626
/// <returns>The <see cref="ILocatable"/> of the <see cref="IWebElement"/>.</returns>
606
- protected static ILocatable GetLocatableFromElement ( IWebElement element )
627
+ [ return : NotNullIfNotNull ( nameof ( element ) ) ]
628
+ protected static ILocatable ? GetLocatableFromElement ( IWebElement ? element )
607
629
{
608
630
if ( element == null )
609
631
{
610
632
return null ;
611
633
}
612
634
613
- ILocatable target = null ;
614
- IWrapsElement wrapper = element as IWrapsElement ;
635
+ ILocatable ? target = null ;
636
+ IWrapsElement ? wrapper = element as IWrapsElement ;
615
637
while ( wrapper != null )
616
638
{
617
639
target = wrapper . WrappedElement as ILocatable ;
@@ -631,12 +653,12 @@ protected static ILocatable GetLocatableFromElement(IWebElement element)
631
653
return target ;
632
654
}
633
655
634
- private T GetDriverAs < T > ( IWebDriver driver ) where T : class
656
+ private static T ? GetDriverAs < T > ( IWebDriver ? driver ) where T : class
635
657
{
636
- T driverAsType = driver as T ;
658
+ T ? driverAsType = driver as T ;
637
659
if ( driverAsType == null )
638
660
{
639
- IWrapsDriver wrapper = driver as IWrapsDriver ;
661
+ IWrapsDriver ? wrapper = driver as IWrapsDriver ;
640
662
while ( wrapper != null )
641
663
{
642
664
driverAsType = wrapper . WrappedDriver as T ;
0 commit comments