Jump to content

WebDriver UDF (W3C compliant version) - 07/29/2022


Recommended Posts

1 hour ago, alexmerfi said:

Firefox 61.0 64 bit, Hyperv Windows 10 x32

Autoit 3.3.14.2

Does it fail for you every time in this environment? If so, please change $_WD_DEBUG = True and post the contents of the Scite output window after running your code.

Also, is there a reason you aren't running the latest version of Autoit?

1 hour ago, alexmerfi said:
If $HandleTab<>'' then MsgBox(0,"","Table IS EXIST, because it return value of handle")
 _WD_Window($sSession, 'Switch', '{"handle":"' & $HandleTab & '"}')
EndIf

But the current implementation should return the handle of the last tab (even if the newest one hasn't appeared as you previously indicated). So $HandleTab would only be blank if there was an error from _WD_ExecuteScript.

 

1 hour ago, alexmerfi said:

Why Wrong? 

if i change timeout 5000 to 0

If TimerDiff($TimerNewTab) > 0 Then Return SetError($_WD_ERROR_Success, 0, $sTabHandle)

i return $HandleTab='' (nothing)

Actually, I meant the error code, not the return value. I would use $_WD_ERROR_Timeout here instead of $_WD_ERROR_Success

59 minutes ago, alexmerfi said:

Yes, you're right, I have not yet found how to fix this inside this function. Perhaps, if the _WD_ExecuteScript will store errors in the global variable, and I will check it through

Shouldn't be necessary to use a global here. Look at other instance where the value of @error is saved to $iErr.

Link to post
Share on other sites
  • Replies 1.1k
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

Introduction This UDF will allow you to interact with any browser that supports the W3C WebDriver specifications. Supporting multiple browsers via the same code base is now possible with just a f

Latest update just released. See below for change log.  

Latest update just released. See below for change log.  

Posted Images

I've been using this with SalesForce and have a decent amount of luck with it.

 

I needed to make a couple changes to two functions so far

_WD_FrameEnter()  SalesForce has many nested Frames and I needed to remove the $_WD_ELEMENT_ID in order to access any frame.

; #FUNCTION# ====================================================================================================================
; Name ..........: _WD_FrameEnter
; Description ...: This will enter the specified frame for subsequent WebDriver operations.
; Syntax ........: _WD_FrameEnter($sIndexOrID)
; Parameters ....:
; Return values .: Success      - True
;                  Failure      - WD Response error message (E.g. "no such frame")
; Author ........: Decibel
; Modified ......: 2018-04-27
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _WD_FrameEnter($sSession, $sIndexOrID)
    Local $sOption
    Local $sResponse, $sJSON
    Local $sValue

    ;*** Encapsulate the value if it's an integer, assuming that it's supposed to be an Index, not ID attrib value.
    If IsInt($sIndexOrID) = True Then
        $sOption = '{"id":' & $sIndexOrID & '}'
    Else
;~      $sOption = '{"id":{"' & $_WD_ELEMENT_ID & '":"' & $sIndexOrID & '"}}'   ;This won't work with Salesforce for some reason
        $sOption = '{"id":"' & $sIndexOrID & '"}'
    EndIf

    $sResponse = _WD_Window($sSession, "frame", $sOption)
    $sJSON = Json_Decode($sResponse)
    $sValue = Json_Get($sJSON, "[value]")

    ;*** Evaluate the response
    If $sValue <> Null Then
        $sValue = Json_Get($sJSON, "[value][error]")
    Else
        $sValue = True
    EndIf

    Return $sValue
EndFunc ;==>_WD_FrameEnter

 

 

Since SalesForce can take a long time to load some pages and controls, I'm using _WD_WaitElement a lot, so I updated it to return the Element(s) once it finally shows up.

; #FUNCTION# ====================================================================================================================
; Name ..........: _WD_WaitElement
; Description ...: Wait for a element to be found  in the current tab before returning
; Syntax ........: _WD_WaitElement($sSession, $sElement, $sStrategy, $sSelector[, $iDelay = 0[, $iTimeout = -1]])
; Parameters ....: $sSession            - Session ID from _WDCreateSession
;                  $sStrategy           - Locator strategy. See defined constant $_WD_LOCATOR_* for allowed values
;                  $sSelector           - Value to find
;                  $sStartElement       - [optional] a string value. Default is "".
;                  $lMultiple           - [optional] True returns Array of Element ID's. Default is False.
;                  $iDelay              - [optional] Milliseconds to wait before checking status
;                  $iTimeout            - [optional] Period of time to wait before exiting function
; Return values .: Success      - Element ID(s) returned by web driver
;                  Failure      - 0 and sets the @error flag to non-zero
;                  @error       - $_WD_ERROR_Success
;                               - $_WD_ERROR_Timeout
; Author ........: Dan Pollak
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _WD_WaitElement($sSession, $sStrategy, $sSelector, $sStartElement = "", $lMultiple = False, $iDelay = 0, $iTimeout = -1)
    Local Const $sFuncName = "_WD_WaitElement"
    Local $bAbort = False, $iErr, $iResult

    If $iTimeout = -1 Then $iTimeout = $_WD_DefaultTimeout

    Sleep($iDelay)

    Local $hWaitTimer = TimerInit()

    While 1
        $FindRet = _WD_FindElement($sSession, $sStrategy, $sSelector, $sStartElement, $lMultiple)
        $iErr = @error

        If $iErr = $_WD_ERROR_Success Then
            $iResult = 1
            ExitLoop

        ElseIf $iErr = $_WD_ERROR_NoMatch Then
            If (TimerDiff($hWaitTimer) > $iTimeout) Then
                $iErr = $_WD_ERROR_Timeout
                ExitLoop
            EndIf
        Else
            ExitLoop
        EndIf

        Sleep(1000)
    WEnd

    Return SetError(__WD_Error($sFuncName, $iErr), $iResult, $FindRet)
EndFunc

 

Link to post
Share on other sites

@BigDaddyO Based on my limited testing, I believe the issue lies with Chromedriver not conforming to the W3C specs. Firefox works fine with the UDF as-is, but fails when I implement your change. Chrome failed for me either way, returning

__WD_Post: StatusCode=500; ResponseText={"value":{"error":"unknown error","message":"missing 'ELEMENT'(Session infochrome=67.0.3396.99)","stacktrace":"Backtrace:\n\tOrdinal0 [0x00C0DF70+778096]\n\tOrdinal0 [0x00BBB42D+439341]\n\tOrdinal0 [0x00B9807F+295039]\n\tOrdinal0 [0x00B80619+198169]\n\tOrdinal0 [0x00B78349+164681]\n\tOrdinal0 [0x00B7F96B+194923]\n\tOrdinal0 [0x00B7824F+164431]\n\tOrdinal0 [0x00B61B45+72517]\n\tOrdinal0 [0x00B62F2A+77610]\n\tOrdinal0 [0x00B62ECC+77516]\n\tGetHandleVerifier [0x00CA9936+3478]\n\tOrdinal0 [0x00C188C3+821443]\n\tOrdinal0 [0x00BC7066+487526]\n\tOrdinal0 [0x00BC7393+488339]\n\tOrdinal0 [0x00BC74A3+488611]\n\tOrdinal0 [0x00C1AA67+830055]\n\tOrdinal0 [0x00BC6DAF+486831]\n\tOrdinal0 [0x00BD13FE+529406]\n\tOrdinal0 [0x00BDC57B+574843]\n\tOrdinal0 [0x00BDC6CD+575181]\n\tOrdinal0 [0x00BDB92B+571691]\n\tBaseThreadInitThunk [0x75FA8484+36]\n\tRtlValidSecurityDescriptor [0x77362FEA+282]\n\tRtlValidSecurityDescriptor [0x77362FBA+234]\n"}}

in one case and

__WD_Post: StatusCode=404; ResponseText={"value":{"error":"no such frame","message":"(Session infochrome=67.0.3396.99)","stacktrace":"Backtrace:\n\tOrdinal0 [0x00C0DF70+778096]\n\tOrdinal0 [0x00BBB42D+439341]\n\tOrdinal0 [0x00B97E1D+294429]\n\tOrdinal0 [0x00B9A2C1+303809]\n\tOrdinal0 [0x00B80787+198535]\n\tOrdinal0 [0x00B78349+164681]\n\tOrdinal0 [0x00B7F96B+194923]\n\tOrdinal0 [0x00B7824F+164431]\n\tOrdinal0 [0x00B61B45+72517]\n\tOrdinal0 [0x00B62F2A+77610]\n\tOrdinal0 [0x00B62ECC+77516]\n\tGetHandleVerifier [0x00CA9936+3478]\n\tOrdinal0 [0x00C188C3+821443]\n\tOrdinal0 [0x00BC7066+487526]\n\tOrdinal0 [0x00BC7393+488339]\n\tOrdinal0 [0x00BC74A3+488611]\n\tOrdinal0 [0x00C1AA67+830055]\n\tOrdinal0 [0x00BC6DAF+486831]\n\tOrdinal0 [0x00BD13FE+529406]\n\tOrdinal0 [0x00BDC57B+574843]\n\tOrdinal0 [0x00BDC6CD+575181]\n\tOrdinal0 [0x00BDB92B+571691]\n\tBaseThreadInitThunk [0x75FA8484+36]\n\tRtlValidSecurityDescriptor [0x77362FEA+282]\n\tRtlValidSecurityDescriptor [0x77362FBA+234]\n"}}

in the other.

Edit: Seems they are already aware of the issue.

Edited by Danp2
Link to post
Share on other sites

@BigDaddyO Regarding the enhancements to _WD_WaitElement, I understand the addition of the optional parameters to take full advantage of _WD_FindElement.

Not sure I see the real benefit of returning the found elements. Please elaborate on how you are using this and why you this change is more desirable than making another call to _WD_FindElement.

Link to post
Share on other sites
8 hours ago, Danp2 said:

@BigDaddyO Regarding the enhancements to _WD_WaitElement, I understand the addition of the optional parameters to take full advantage of _WD_FindElement.

Not sure I see the real benefit of returning the found elements. Please elaborate on how you are using this and why you this change is more desirable than making another call to _WD_FindElement.

I guess because I'm lazy and don't want to write another line when the _WD_WaitElement just performed the _WD_FindElement command. 

Granted, the extra two options "", True in the function are a little annoying, perhaps putting those to the end since someone would most likely use the Delay and Wait options more often.

Link to post
Share on other sites
  • 3 weeks later...

@Danp2 I created a _WD_WaitElementVisible() function based off your _WD_WaitElement() function.

For most elements I don't need this, but I came across a popup that seems to get created and is hidden in the background after logging into the website so the _WD_WaitElement() returned right away.  I needed to create this so it will wait for the element to exist AND be visible.  I included the link to where I found the code which is apparently what the JQuery code .is(':visible') uses.

OLD  updated function is 2 posts below!

; #FUNCTION# ====================================================================================================================
; Name ..........: _WD_WaitElementVisible
; Description ...: Wait for a element to be found in the current tab and that its visible before returning
; Syntax ........: _WD_WaitElementVisible($sSession, $sElement, $sStrategy, $sSelector[, $iDelay = 0[, $iTimeout = -1]])
; Parameters ....: $sSession            - Session ID from _WDCreateSession
;                  $sStrategy           - Locator strategy. See defined constant $_WD_LOCATOR_* for allowed values
;                  $sSelector           - Value to find
;                  $iDelay              - [optional] Milliseconds to wait before checking status
;                  $iTimeout            - [optional] Period of time to wait before exiting function
; Return values .: Success      - 1
;                  Failure      - 0 and sets the @error flag to non-zero
;                  @error       - $_WD_ERROR_Success
;                               - $_WD_ERROR_Timeout
; Author ........: Dan Pollak, BigDaddyO added visible
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........: https://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom/28933648
; Example .......: No
; ===============================================================================================================================
Func _WD_WaitElementVisible($sSession, $sStrategy, $sSelector, $iDelay = 0, $iTimeout = -1)
    Local Const $sFuncName = "_WD_WaitElement"
    Local $bAbort = False, $iErr, $iResult

    If $iTimeout = -1 Then $iTimeout = $_WD_DefaultTimeout

    Sleep($iDelay)

    Local $hWaitTimer = TimerInit()

    While 1
        $FindRet = _WD_FindElement($sSession, $sStrategy, $sSelector)
        $iErr = @error

        If $iErr = $_WD_ERROR_Success Then
            Local $sJsonElement = '{"' & $_WD_ELEMENT_ID & '":"' & $FindRet & '"}'
            $sResponse = _WD_ExecuteScript($sSession, "return arguments[0].offsetWidth || arguments[0].offsetHeight || arguments[0].getClientRects().length", $sJsonElement)
            ;Not visible returns {"value":0}
            ;Visible returns a # for example {"value":115}
            $sJSON = Json_Decode($sResponse)            ;Use Json_Decode to pull just the value from the response
            $isVisible = Json_Get($sJSON, "[value]")
            If $isVisible > 0 Then
                $iResult = 1
                ExitLoop
            EndIf

        ElseIf $iErr = $_WD_ERROR_NoMatch Then
            If (TimerDiff($hWaitTimer) > $iTimeout) Then
                $iErr = $_WD_ERROR_Timeout
                ExitLoop
            EndIf
        Else
            ExitLoop
        EndIf

        Sleep(1000)
    WEnd

    Return SetError(__WD_Error($sFuncName, $iErr), $iResult)
EndFunc

 

Edited by BigDaddyO
Danp2 found a better option
Link to post
Share on other sites
3 hours ago, Danp2 said:

@BigDaddyO I haven't tested this, but the w3c specs show that you can check the element's visibility like this --

/session/{session id}/element/{element id}/displayed

 

 

That worked! at least in Chrome.  I did have to update the _WD_ElementAction() Function to include 'displayed' as a valid command

    Switch $sCommand
        Case 'name', 'rect', 'text', 'selected', 'enabled', 'displayed'
 

; #FUNCTION# ====================================================================================================================
; Name ..........: _WD_WaitElementVisible
; Description ...: Wait for a element to be found in the current tab and that its visible before returning
; Syntax ........: _WD_WaitElementVisible($sSession, $sElement, $sStrategy, $sSelector[, $iDelay = 0[, $iTimeout = -1]])
; Parameters ....: $sSession            - Session ID from _WDCreateSession
;                  $sStrategy           - Locator strategy. See defined constant $_WD_LOCATOR_* for allowed values
;                  $sSelector           - Value to find
;                  $iDelay              - [optional] Milliseconds to wait before checking status
;                  $iTimeout            - [optional] Period of time to wait before exiting function
; Return values .: Success      - 1
;                  Failure      - 0 and sets the @error flag to non-zero
;                  @error       - $_WD_ERROR_Success
;                               - $_WD_ERROR_Timeout
; Author ........: Dan Pollak
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _WD_WaitElementVisible($sSession, $sStrategy, $sSelector, $iDelay = 0, $iTimeout = -1)
    Local Const $sFuncName = "_WD_WaitElementVisible"
    Local $bAbort = False, $iErr, $iResult, $isVisible

    If $iTimeout = -1 Then $iTimeout = $_WD_DefaultTimeout

    Sleep($iDelay)

    Local $hWaitTimer = TimerInit()

    While 1
        $FindRet = _WD_FindElement($sSession, $sStrategy, $sSelector)
        $iErr = @error

        If $iErr = $_WD_ERROR_Success Then
            $isVisible = _WD_ElementAction($sSession, $FindRet, 'displayed')
            if $isVisible = True Then
                $iResult = 1
                ExitLoop
            EndIf

        ElseIf $iErr = $_WD_ERROR_NoMatch Then
            If (TimerDiff($hWaitTimer) > $iTimeout) Then
                $iErr = $_WD_ERROR_Timeout
                ExitLoop
            EndIf
        Else
            ExitLoop
        EndIf

        Sleep(1000)
    WEnd

    Return SetError(__WD_Error($sFuncName, $iErr), $iResult)
EndFunc

 

Edited by BigDaddyO
change needed to _WD_ElementAction()
Link to post
Share on other sites

Yeah, that would make sense.

I'm not sure yet if it should default to IsVisible or not.  I'm still using my updated _WD_WaitElement that returns an elementID but it gets errors occasionally about stale elements so I have been meaning to change my code back to your Standard, it's just going to be a lot of work.

 

Also, It seems that the function can use = True instead of = "true" so I'm going to update the function in the above post

Link to post
Share on other sites

Here's the revised _WD_WaitElement with the optional visibility check. Seems to work well in my testing. Let me know if you encounter any issues.

; #FUNCTION# ====================================================================================================================
; Name ..........: _WD_WaitElement
; Description ...: Wait for a element to be found  in the current tab before returning
; Syntax ........: _WD_WaitElement($sSession, $sStrategy, $sSelector[, $iDelay = 0[, $iTimeout = -1[, $lVisible = False]]])
; Parameters ....: $sSession            - Session ID from _WDCreateSession
;                  $sStrategy           - Locator strategy. See defined constant $_WD_LOCATOR_* for allowed values
;                  $sSelector           - Value to find
;                  $iDelay              - [optional] Milliseconds to wait before checking status
;                  $iTimeout            - [optional] Period of time to wait before exiting function
;                  $lVisible            - [optional] Check visibility of element?
; Return values .: Success      - 1
;                  Failure      - 0 and sets the @error flag to non-zero
;                  @error       - $_WD_ERROR_Success
;                               - $_WD_ERROR_Timeout
; Author ........: Dan Pollak
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _WD_WaitElement($sSession, $sStrategy, $sSelector, $iDelay = 0, $iTimeout = -1, $lVisible = False)
    Local Const $sFuncName = "_WD_WaitElement"
    Local $bAbort = False, $iErr, $iResult, $sElement, $lIsVisible = True

    If $iTimeout = -1 Then $iTimeout = $_WD_DefaultTimeout

    Sleep($iDelay)

    Local $hWaitTimer = TimerInit()

    While 1
        $sElement = _WD_FindElement($sSession, $sStrategy, $sSelector)
        $iErr = @error

        If $iErr = $_WD_ERROR_Success Then
            If $lVisible Then
                $lIsVisible = _WD_ElementAction($sSession, $sElement, 'displayed')
            EndIf

            If $lIsVisible = True Then
                $iResult = 1
                ExitLoop
            EndIf

        ElseIf $iErr <> $_WD_ERROR_NoMatch Then
            ExitLoop
        EndIf

        If (TimerDiff($hWaitTimer) > $iTimeout) Then
            $iErr = $_WD_ERROR_Timeout
            ExitLoop
        EndIf

        Sleep(1000)
    WEnd

    Return SetError(__WD_Error($sFuncName, $iErr), $iResult)
EndFunc

 

Link to post
Share on other sites

Looks like the Return isn't setup properly in the _WD_WaitElement() 

It is returning the $iResult in @Extended.  I think it should be something like this:  Return SetError(__WD_Error($sFuncName, $iErr), 0, $iResult)

 

Also, in the Local line, should $iResult be preset to 0 to return 0 if it errors?

Edited by BigDaddyO
Link to post
Share on other sites
  • Danp2 changed the title to WebDriver UDF (W3C compliant version) - 07/29/2022

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By TTE26
      For the past two days I've been reading all Wiki pages, installed all the demos etc. but I am still unable to do this simple workflow
      1. I want to use WebDriver UDF to open Chrome (Set chrome option arguments - Window Size, Pixel ratio, device type and platform name, user-agent.)
      2. On new Tab I want to read the tab Title and save it into a TXT file.
      3. I need to save the Session ID with my previosly set Capabilities into a file.
      4. I want to close the chrome window.
      Then
      5. I want to open Chrome again, but with my previosly saved Session ID and Capabilities list from the file.
      6. And minimaze the window state.
      7. After 30 seconds, close the chrome.
      I would really appreciate for the WebDriver UDF Helper file, to have also basic code examples, for non coders. For example how to open a windwow etc., save sessions, etc.
      Anyway, if someone could help me get started and help me with this workflow, that would be much appreaciated. 😔
    • By lapoelkan12
      hi i try to use webdriver  i download it and  download json and  winhttp i try to run it  but  return error
       error: __WinHttpVer(): undefined function.
              Local $sWinHttpVer = __WinHttpVer()
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
       
       

    • By levila
      Hi Guys, i just do some codding to automate login to some of the web.
      I manage to do the script but somehow after script done, some weird box popup. and keep looping until i close the main chrome.exe

      here is my code. kinldy pls assist, im very new to webdriver udf.
      #NoTrayIcon #include "wd_core.au3" #include "wd_helper.au3" $_WD_DEBUG = $_WD_DEBUG_None ; You could also use $_WD_DEBUG_Error Local $sDesiredCapabilities, $sSession SetupChrome() _WD_Startup() $sSession = _WD_CreateSession($sDesiredCapabilities) _WD_Navigate($sSession, "https://someoftheweb.com") _ChromeSetInputValueByName($sSession, "inputName", "Username") _ChromeSetInputValueById($sSession, "inputPassword", "Password") _ChromeSetMouseClick($sSession, "submit", "click") _WD_Shutdown() Func SetupChrome() _WD_Option('Driver', 'chromedriver.exe') _WD_Option('Port', 9515) _WD_Option('DriverParams', '--log-path="' & @ScriptDir & '\chrome.log"') $sDesiredCapabilities = '{"capabilities": {"alwaysMatch": {"goog:chromeOptions": {"w3c": true, "args":["--no-sandbox"]}}}}' EndFunc Func _ChromeSetInputValueByName($sSession,$name,$Value) $sButton = _WD_FindElement($sSession, $_WD_LOCATOR_ByXPath, "//input[@id='"&$name&"']") _WD_ElementAction($sSession,$sButton,'value', $Value) EndFunc Func _ChromeSetInputValueById($sSession,$Id,$Value) $sButton = _WD_FindElement($sSession, $_WD_LOCATOR_ByXPath, "//input[@id='"&$Id&"']") _WD_ElementAction($sSession,$sButton,'value', $Value) EndFunc Func _ChromeSetMouseClick($sSession,$Id,$Value) $sButton = _WD_FindElement($sSession,$_WD_LOCATOR_ByXPath,"//button[@type='"&$Id&"']") _WD_ElementAction($sSession, $sButton, 'click', $Value) EndFunc  
    • By RohanM
      Hi Team,
      is there is a way to embed the webpage in auto it GUI using webdriver? what I want to do is that, I want to open edge browser inside the AutoIT GUI, in IE we have _IECreateEmbedded function but for the webdriver I am not able to find a function, please help  
      Rohan M
    • By goku200
      I am trying to change the settings of the print option to Save as PDF and its not changing the settings and clicking on the Save button at the bottom. Here is my script that I have written and the format is correct below. Chrome browser I'm using is 97.0 My script was working fine using Chrome 95.0\ Not sure why its not working now
      It finds the print-preview-app element but not the others.
       
×
×
  • Create New...