1919
2020using System ;
2121using System . Collections . Generic ;
22+ using System . Diagnostics . CodeAnalysis ;
23+
24+ #nullable enable
2225
2326namespace OpenQA . Selenium . Interactions
2427{
@@ -29,9 +32,9 @@ public class Actions : IAction
2932 {
3033 private readonly TimeSpan duration ;
3134 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 ;
3538
3639 /// <summary>
3740 /// Initializes a new instance of the <see cref="Actions"/> class.
@@ -51,14 +54,10 @@ public Actions(IWebDriver driver)
5154 /// <exception cref="ArgumentException">If <paramref name="driver"/> does not implement <see cref="IActionExecutor"/>.</exception>
5255 public Actions ( IWebDriver driver , TimeSpan duration )
5356 {
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 ) ) ;
5959
6060 this . ActionExecutor = actionExecutor ;
61-
6261 this . duration = duration ;
6362 }
6463
@@ -74,9 +73,10 @@ public Actions(IWebDriver driver, TimeSpan duration)
7473 /// <param name="name">The name of the pointer device to set as active.</param>
7574 /// <returns>A self-reference to this Actions class.</returns>
7675 /// <exception cref="InvalidOperationException">If a device with this name exists but is not a pointer.</exception>
76+ [ MemberNotNull ( nameof ( activePointer ) ) ]
7777 public Actions SetActivePointer ( PointerKind kind , string name )
7878 {
79- InputDevice device = FindDeviceById ( name ) ;
79+ InputDevice ? device = FindDeviceById ( name ) ;
8080
8181 this . activePointer = device switch
8282 {
@@ -94,9 +94,10 @@ public Actions SetActivePointer(PointerKind kind, string name)
9494 /// <param name="name">The name of the keyboard device to set as active.</param>
9595 /// <returns>A self-reference to this Actions class.</returns>
9696 /// <exception cref="InvalidOperationException">If a device with this name exists but is not a keyboard.</exception>
97+ [ MemberNotNull ( nameof ( activeKeyboard ) ) ]
9798 public Actions SetActiveKeyboard ( string name )
9899 {
99- InputDevice device = FindDeviceById ( name ) ;
100+ InputDevice ? device = FindDeviceById ( name ) ;
100101
101102 this . activeKeyboard = device switch
102103 {
@@ -114,9 +115,10 @@ public Actions SetActiveKeyboard(string name)
114115 /// <param name="name">The name of the wheel device to set as active.</param>
115116 /// <returns>A self-reference to this Actions class.</returns>
116117 /// <exception cref="InvalidOperationException">If a device with this name exists but is not a wheel.</exception>
118+ [ MemberNotNull ( nameof ( activeWheel ) ) ]
117119 public Actions SetActiveWheel ( string name )
118120 {
119- InputDevice device = FindDeviceById ( name ) ;
121+ InputDevice ? device = FindDeviceById ( name ) ;
120122
121123 this . activeWheel = device switch
122124 {
@@ -128,7 +130,7 @@ public Actions SetActiveWheel(string name)
128130 return this ;
129131 }
130132
131- private InputDevice FindDeviceById ( string name )
133+ private InputDevice ? FindDeviceById ( string ? name )
132134 {
133135 foreach ( var sequence in this . actionBuilder . ToActionSequenceList ( ) )
134136 {
@@ -211,14 +213,14 @@ public Actions KeyDown(string theKey)
211213 /// of <see cref="Keys.Shift"/>, <see cref="Keys.Control"/>, <see cref="Keys.Alt"/>,
212214 /// <see cref="Keys.Meta"/>, <see cref="Keys.Command"/>,<see cref="Keys.LeftAlt"/>,
213215 /// <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 )
215217 {
216218 if ( string . IsNullOrEmpty ( theKey ) )
217219 {
218220 throw new ArgumentException ( "The key value must not be null or empty" , nameof ( theKey ) ) ;
219221 }
220222
221- ILocatable target = GetLocatableFromElement ( element ) ;
223+ ILocatable ? target = GetLocatableFromElement ( element ) ;
222224 if ( element != null )
223225 {
224226 this . actionBuilder . AddAction ( this . GetActivePointer ( ) . CreatePointerMove ( element , 0 , 0 , duration ) ) ;
@@ -255,14 +257,14 @@ public Actions KeyUp(string theKey)
255257 /// of <see cref="Keys.Shift"/>, <see cref="Keys.Control"/>, <see cref="Keys.Alt"/>,
256258 /// <see cref="Keys.Meta"/>, <see cref="Keys.Command"/>,<see cref="Keys.LeftAlt"/>,
257259 /// <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 )
259261 {
260262 if ( string . IsNullOrEmpty ( theKey ) )
261263 {
262264 throw new ArgumentException ( "The key value must not be null or empty" , nameof ( theKey ) ) ;
263265 }
264266
265- ILocatable target = GetLocatableFromElement ( element ) ;
267+ ILocatable ? target = GetLocatableFromElement ( element ) ;
266268 if ( element != null )
267269 {
268270 this . actionBuilder . AddAction ( this . GetActivePointer ( ) . CreatePointerMove ( element , 0 , 0 , duration ) ) ;
@@ -279,6 +281,7 @@ public Actions KeyUp(IWebElement element, string theKey)
279281 /// </summary>
280282 /// <param name="keysToSend">The keystrokes to send to the browser.</param>
281283 /// <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>
282285 public Actions SendKeys ( string keysToSend )
283286 {
284287 return this . SendKeys ( null , keysToSend ) ;
@@ -290,14 +293,15 @@ public Actions SendKeys(string keysToSend)
290293 /// <param name="element">The element to which to send the keystrokes.</param>
291294 /// <param name="keysToSend">The keystrokes to send to the browser.</param>
292295 /// <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 )
294298 {
295299 if ( string . IsNullOrEmpty ( keysToSend ) )
296300 {
297301 throw new ArgumentException ( "The key value must not be null or empty" , nameof ( keysToSend ) ) ;
298302 }
299303
300- ILocatable target = GetLocatableFromElement ( element ) ;
304+ ILocatable ? target = GetLocatableFromElement ( element ) ;
301305 if ( element != null )
302306 {
303307 this . actionBuilder . AddAction ( this . GetActivePointer ( ) . CreatePointerMove ( element , 0 , 0 , duration ) ) ;
@@ -319,6 +323,7 @@ public Actions SendKeys(IWebElement element, string keysToSend)
319323 /// </summary>
320324 /// <param name="onElement">The element on which to click and hold.</param>
321325 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
326+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
322327 public Actions ClickAndHold ( IWebElement onElement )
323328 {
324329 this . MoveToElement ( onElement ) . ClickAndHold ( ) ;
@@ -340,6 +345,7 @@ public Actions ClickAndHold()
340345 /// </summary>
341346 /// <param name="onElement">The element on which to release the button.</param>
342347 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
348+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
343349 public Actions Release ( IWebElement onElement )
344350 {
345351 this . MoveToElement ( onElement ) . Release ( ) ;
@@ -361,6 +367,7 @@ public Actions Release()
361367 /// </summary>
362368 /// <param name="onElement">The element on which to click.</param>
363369 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
370+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
364371 public Actions Click ( IWebElement onElement )
365372 {
366373 this . MoveToElement ( onElement ) . Click ( ) ;
@@ -383,6 +390,7 @@ public Actions Click()
383390 /// </summary>
384391 /// <param name="onElement">The element on which to double-click.</param>
385392 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
393+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
386394 public Actions DoubleClick ( IWebElement onElement )
387395 {
388396 this . MoveToElement ( onElement ) . DoubleClick ( ) ;
@@ -407,6 +415,7 @@ public Actions DoubleClick()
407415 /// </summary>
408416 /// <param name="toElement">The element to which to move the mouse.</param>
409417 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
418+ /// <exception cref="ArgumentNullException">If <paramref name="toElement"/> is null.</exception>
410419 public Actions MoveToElement ( IWebElement toElement )
411420 {
412421 if ( toElement == null )
@@ -460,6 +469,7 @@ public Actions MoveToLocation(int offsetX, int offsetY)
460469 /// </summary>
461470 /// <param name="onElement">The element on which to right-click.</param>
462471 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
472+ /// <exception cref="ArgumentNullException">If <paramref name="onElement"/> is null.</exception>
463473 public Actions ContextClick ( IWebElement onElement )
464474 {
465475 this . MoveToElement ( onElement ) . ContextClick ( ) ;
@@ -483,6 +493,7 @@ public Actions ContextClick()
483493 /// <param name="source">The element on which the drag operation is started.</param>
484494 /// <param name="target">The element on which the drop is performed.</param>
485495 /// <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>
486497 public Actions DragAndDrop ( IWebElement source , IWebElement target )
487498 {
488499 this . ClickAndHold ( source ) . MoveToElement ( target ) . Release ( target ) ;
@@ -496,6 +507,7 @@ public Actions DragAndDrop(IWebElement source, IWebElement target)
496507 /// <param name="offsetX">The horizontal offset to which to move the mouse.</param>
497508 /// <param name="offsetY">The vertical offset to which to move the mouse.</param>
498509 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
510+ /// <exception cref="ArgumentNullException">If <paramref name="source"/> is null.</exception>
499511 public Actions DragAndDropToOffset ( IWebElement source , int offsetX , int offsetY )
500512 {
501513 this . ClickAndHold ( source ) . MoveByOffset ( offsetX , offsetY ) . Release ( ) ;
@@ -507,6 +519,7 @@ public Actions DragAndDropToOffset(IWebElement source, int offsetX, int offsetY)
507519 /// </summary>
508520 /// <param name="element">Which element to scroll into the viewport.</param>
509521 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
522+ /// <exception cref="ArgumentNullException">If <paramref name="element"/> is null.</exception>
510523 public Actions ScrollToElement ( IWebElement element )
511524 {
512525 this . actionBuilder . AddAction ( this . GetActiveWheel ( ) . CreateWheelScroll ( element , 0 , 0 , 0 , 0 , duration ) ) ;
@@ -540,8 +553,15 @@ public Actions ScrollByAmount(int deltaX, int deltaY)
540553 /// <param name="deltaY">Distance along Y axis to scroll using the wheel. A negative value scrolls up.</param>
541554 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
542555 /// <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>
543558 public Actions ScrollFromOrigin ( WheelInputDevice . ScrollOrigin scrollOrigin , int deltaX , int deltaY )
544559 {
560+ if ( scrollOrigin is null )
561+ {
562+ throw new ArgumentNullException ( nameof ( scrollOrigin ) ) ;
563+ }
564+
545565 if ( scrollOrigin . Viewport && scrollOrigin . Element != null )
546566 {
547567 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
554574 }
555575 else
556576 {
557- this . actionBuilder . AddAction ( this . GetActiveWheel ( ) . CreateWheelScroll ( scrollOrigin . Element ,
577+ this . actionBuilder . AddAction ( this . GetActiveWheel ( ) . CreateWheelScroll ( scrollOrigin . Element ! ,
558578 scrollOrigin . XOffset , scrollOrigin . YOffset , deltaX , deltaY , duration ) ) ;
559579 }
560580
@@ -566,6 +586,7 @@ public Actions ScrollFromOrigin(WheelInputDevice.ScrollOrigin scrollOrigin, int
566586 /// </summary>
567587 /// <param name="duration">How long to pause the action chain.</param>
568588 /// <returns>A self-reference to this <see cref="Actions"/>.</returns>
589+ /// <exception cref="ArgumentException">If <paramref name="duration"/> is negative.</exception>
569590 public Actions Pause ( TimeSpan duration )
570591 {
571592 this . actionBuilder . AddAction ( new PauseInteraction ( this . GetActivePointer ( ) , duration ) ) ;
@@ -603,15 +624,16 @@ public void Reset()
603624 /// </summary>
604625 /// <param name="element">The <see cref="IWebElement"/> to get the location of.</param>
605626 /// <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 )
607629 {
608630 if ( element == null )
609631 {
610632 return null ;
611633 }
612634
613- ILocatable target = null ;
614- IWrapsElement wrapper = element as IWrapsElement ;
635+ ILocatable ? target = null ;
636+ IWrapsElement ? wrapper = element as IWrapsElement ;
615637 while ( wrapper != null )
616638 {
617639 target = wrapper . WrappedElement as ILocatable ;
@@ -631,12 +653,12 @@ protected static ILocatable GetLocatableFromElement(IWebElement element)
631653 return target ;
632654 }
633655
634- private T GetDriverAs < T > ( IWebDriver driver ) where T : class
656+ private static T ? GetDriverAs < T > ( IWebDriver ? driver ) where T : class
635657 {
636- T driverAsType = driver as T ;
658+ T ? driverAsType = driver as T ;
637659 if ( driverAsType == null )
638660 {
639- IWrapsDriver wrapper = driver as IWrapsDriver ;
661+ IWrapsDriver ? wrapper = driver as IWrapsDriver ;
640662 while ( wrapper != null )
641663 {
642664 driverAsType = wrapper . WrappedDriver as T ;
0 commit comments