Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Method. ExecuteScript #24

Closed
ghost opened this issue Sep 16, 2021 · 18 comments
Closed

Add Method. ExecuteScript #24

ghost opened this issue Sep 16, 2021 · 18 comments

Comments

@ghost
Copy link

ghost commented Sep 16, 2021

TinySeleniumVBA WebDriver.cls

' Execute Script                '2021/7/4 add ishi -> 2021/07/20 chg ishi
Public Function ExecuteScript(Script As String, _
                              Optional args As Variant, _
                              Optional ByVal sessionId As String = vbNullString)
    Dim data    As New Dictionary
    data.Add "script", Script
    
    If VarType(args) <> vbVariant + vbArray Then    'args is Array
        args = Array()
    End If
    data.Add "args", args
    
    If sessionId = vbNullString Then
        data.Add "sessionId", DefaultSessionId
    Else
        data.Add "sessionId", sessionId
    End If
    
    ' Set Method and Path
    Dim method As String: method = CMD_W3C_EXECUTE_SCRIPT(0)
    Dim path As String: path = CMD_W3C_EXECUTE_SCRIPT(1)
    
    ' Set params to path
    Dim dataKey As Variant
    For Each dataKey In data
        If VarType(data(dataKey)) = vbString Then
            path = Replace(path, "$" + dataKey, data(dataKey))
        End If
    Next

    ' Send request to selenium server
    Dim resp As Dictionary
    Set resp = SendRequest(method, UrlBase + path, data)
    
    ' Return
    If IsNull(resp("value")) Then
        ExecuteScript = vbNullString        'Return vbnNullString
    ElseIf TypeName(resp("value")) = "Collection" Then
        Set ExecuteScript = resp("value")
    ElseIf VarType(resp("value")) = vbObject Then
        If resp("value").Exists("error") Then
            Err.Raise 513, "WebDriver.Execute", JsonConverter.ConvertToJson(resp("value"))
        Else
            Set ExecuteScript = resp("value")
        End If
    Else
        ExecuteScript = resp("value")
    End If
End Function
@ghost
Copy link
Author

ghost commented Oct 2, 2021

ExecuteScriptを直接呼び出す際のElementIDへの配慮を加えた『ExecuteScript』です。
javascriptに渡す引数はScriptargsで指定です。引数が複数ある場合はScriptargsに配列で渡して下さい。
この対応に伴い『SelectByIndex』『DeSelectByIndex』に変更があります。
(Add Method. Select operations #17 commented 1)

TinySeleniumVBA WebDriver.cls

' Execute Script                '2021/7/4 add ishi -> 2021/07/20 chg ishi -> 2021/9/30 chg ishi
Public Function ExecuteScript(Script As String, _
                              Optional Scriptargs As Variant = vbNullString, _
                              Optional ElementId As String = vbNullString, _
                              Optional ByVal sessionId As String = vbNullString)
    Dim Data    As New Dictionary
    Data.Add "script", Script
    
    ' Set ElementID and Args
    Dim ElmData As New Dictionary
    Dim args    As Variant
    If ElementId <> vbNullString Then
        ElmData.Add "ELEMENT", ElementId
        ElmData.Add ELEMENT_KEY, ElementId
        args = Array(ElmData)
        If VarType(Scriptargs) = vbVariant + vbArray Then    'Scriptargs is Array
            Dim i As Integer
            For i = 0 To UBound(Scriptargs)
                ReDim Preserve args(i + 1)
                args(i + 1) = Scriptargs(i)
            Next
        Else
            args = Array(ElmData, Scriptargs)
        End If
    Else
        args = Array()
    End If
    Data.Add "args", args
    
    ' Set sessionId
    If sessionId = vbNullString Then
        Data.Add "sessionId", DefaultSessionId
    Else
        Data.Add "sessionId", sessionId
    End If
    
    ' Set Method and Path
    Dim method As String: method = CMD_W3C_EXECUTE_SCRIPT(0)
    Dim path As String: path = CMD_W3C_EXECUTE_SCRIPT(1)
    
    ' Set params to path
    Dim dataKey As Variant
    For Each dataKey In Data
        If VarType(Data(dataKey)) = vbString Then
            path = Replace(path, "$" + dataKey, Data(dataKey))
        End If
    Next

    ' Send request to selenium server
    Dim resp As Dictionary
    Set resp = SendRequest(method, UrlBase + path, Data)
    
    ' Return
    If IsNull(resp("value")) Then
        ExecuteScript = vbNullString        'Return vbnNullString
    ElseIf TypeName(resp("value")) = "Collection" Then
        Set ExecuteScript = resp("value")
    ElseIf VarType(resp("value")) = vbObject Then
        If resp("value").Exists("error") Then
            Err.Raise 513, "WebDriver.Execute", JsonConverter.ConvertToJson(resp("value"))
        Else
            Set ExecuteScript = resp("value")
        End If
    Else
        ExecuteScript = resp("value")
    End If
End Function

TinySeleniumVBA WebElement.cls

' ExecuteScript                     '2021/9/30 add ishi
Public Function ExecuteScript(Script As String, _
                              Optional Scriptargs As Variant = vbNullString)
    Driver_.ExecuteScript Script, Scriptargs, ElementId_, SessionId_
End Function

@ghost ghost changed the title Method. ExecuteScript Add Method. ExecuteScript Oct 23, 2021
@ghost
Copy link
Author

ghost commented Oct 24, 2021

WebElement.cls の ExecuteScript で戻値への配慮が漏れていましたので見直しました。

TinySeleniumVBA WebElement.cls

' ExecuteScript                     '2021/9/30 add ishi -> 2021/10/24 chg ishi
Public Function ExecuteScript(Script As String, _
                              Optional ScriptArgs As Variant = vbNullString)
    ExecuteScript = Driver_.ExecuteScript(Script, ScriptArgs, ElementId_, SessionId_)
End Function

@GCuser99
Copy link

GCuser99 commented Dec 30, 2021

Nice contribution @ezagdd . I think (but am not sure?) that ExecuteScript could be simplified to the following below. Note that I added optional timeout and raise input parameters as in here. The only functional difference that I can see between the version below and yours above, aside from the raise and timeout parameters, is the return type if IsNull(resp("value")) condition of the script is true. This version returns an empty Dictionary and yours a null string.

Public Function ExecuteScript(ByVal Script As String, Optional ScriptArgs As Variant = vbNullString, Optional ByVal ElementId As String = vbNullString, Optional ByVal SessionId As String = vbNullString, Optional ByVal timeOutms, Optional ByVal raise As Boolean = True)
    Dim Data As New Dictionary, ElmData As New Dictionary, args As Variant

    Data.Add "script", Script
    
    ' Set ElementID and Args
    If ElementId <> vbNullString Then
        ElmData.Add "ELEMENT", ElementId
        ElmData.Add ELEMENT_KEY, ElementId
        args = Array(ElmData)
        If VarType(ScriptArgs) = vbVariant + vbArray Then    'Scriptargs is Array
            Dim i As Integer
            For i = 0 To UBound(ScriptArgs)
                ReDim Preserve args(i + 1)
                args(i + 1) = ScriptArgs(i)
            Next
        Else
            args = Array(ElmData, ScriptArgs)
        End If
    Else
        args = Array()
    End If
    Data.Add "args", args
    
    ' Set sessionId
    If SessionId = vbNullString Then
        Data.Add "sessionId", DefaultSessionId
    Else
        Data.Add "sessionId", SessionId
    End If
    
    If Not IsMissing(timeOutms) Then
        savtimeOutms = Me.GetScriptTimeout(SessionId)
        If savtimeOutms <> timeOutms Then Me.SetScriptTimeout timeOutms, SessionId
    End If
    
    ExecuteScript = Execute(CMD_W3C_EXECUTE_SCRIPT, Data, raise)
    
    If Not IsMissing(timeOutms) Then
        If savtimeOutms <> timeOutms Then Me.SetScriptTimeout savtimeOutms, SessionId
    End If
    
End Function

@ghost
Copy link
Author

ghost commented Jan 1, 2022

ExecuteScript 関数を入力する際に timeOutms 引数の属性を明らかにする為に Optional ByVal timeOutms As Double と
しました。
その上で timeOutms と raise が未指定の場合、timeOutms = 0ms で raise = True なので、Script が 0ms 以内に応答が
ない場合 raise エラーになります。そこで Optional ByVal raise As Boolean = False にしました。
また、timeOutms が指定され raise = True の場合( timeOutms > 0 And raise )にのみ、GetScriptTimeout、
SetScriptTimeout を呼び出すようにしました。

Public Function ExecuteScript(ByVal Script As String, _
                              Optional ScriptArgs As Variant = vbNullString, _
                              Optional ByVal ElementId As String = vbNullString, _
                              Optional ByVal SessionId As String = vbNullString, _
                              Optional ByVal timeOutms As Double, _
                              Optional ByVal raise As Boolean = False)
    Dim Data As New Dictionary
    Dim ElmData As New Dictionary
    Dim args As Variant
    Dim savtimeOutms As Double

    Data.Add "script", Script

    ' Set ElementID and Args
    If ElementId <> vbNullString Then
        ElmData.Add "ELEMENT", ElementId
        ElmData.Add ELEMENT_KEY, ElementId
        args = Array(ElmData)
        If VarType(ScriptArgs) = vbVariant + vbArray Then    'Scriptargs is Array
            Dim i As Integer
            For i = 0 To UBound(ScriptArgs)
                ReDim Preserve args(i + 1)
                args(i + 1) = ScriptArgs(i)
            Next
        Else
            args = Array(ElmData, ScriptArgs)
        End If
    Else
        args = Array()
    End If
    Data.Add "args", args

    ' Set sessionId
    If SessionId = vbNullString Then
        Data.Add "sessionId", DefaultSessionId
    Else
        Data.Add "sessionId", SessionId
    End If

    If timeOutms > 0 And raise Then
        savtimeOutms = Me.GetScriptTimeout(SessionId)
        If savtimeOutms <> timeOutms Then Me.SetScriptTimeout timeOutms, SessionId
    End If

    ExecuteScript = Execute(CMD_W3C_EXECUTE_SCRIPT, Data, raise)

    If timeOutms > 0 And raise Then
        If savtimeOutms <> timeOutms Then Me.SetScriptTimeout savtimeOutms, SessionId
    End If

End Function

もしも Optional ByVal timeOutms のままなら、timeOutms を Doubleに変換して SetScriptTimeout を呼出す必要があります。

        If savtimeOutms <> timeOutms Then Me.SetScriptTimeout cDbl(timeOutms), SessionId

 
 
#46 Execute の対応後に、ExecuteScript のテスト用に使ったものです。

Sub TestforScroll()
Dim Driver          As WebDriver    'Chrome WebDriver Instance
Dim height          As Long
Dim scroll          As Long

    Set Driver = New WebDriver
    Driver.Chrome "chromedriver.exe"
    Driver.OpenBrowser

    Driver.Navigate "https://www.yahoo.co.jp/"
    
    'Scroll
    scroll = 0
    Do
        scroll = scroll + 4
        Driver.ExecuteScript "window.scrollTo(0, " & CStr(scroll) & ");"
        'Get Page Height
        height = Driver.ExecuteScript("return document.body.scrollHeight")
        'Over Page Height ?
        If scroll > height Then
            Exit Do
        End If
    Loop

    'Top Scroll
    Driver.ExecuteScript "window.scrollTo(0, 0);"
    Driver.Wait
    
    'Down Scroll
    Driver.ExecuteScript "window.scrollTo(0, document.body.scrollHeight);"
    Driver.Wait

    Driver.CloseBrowser
    Driver.Shutdown
    Set Driver = Nothing
End Sub

@GCuser99
Copy link

GCuser99 commented Jan 1, 2022

Thanks @ezagdd!

In my version (of your original version!) of ExecuteScript, I don't get the error because I had already changed the SetScriptTimeout's optional millisecond parameters to ByVal instead of the default ByRef as in below:

Public Function SetScriptTimeout(Optional ByVal millisecond As Long= 30000, _
                                 Optional ByVal sessionId As String = vbNullString)

Also, consider changing millisecond variable type to Long, unless Selenium really does accept fractions of milliseconds...

In fact, I went through the entire code base and changed any input parameter that was not typed as Object or Variant (such as strongly-typed Double, Long, Boolean, or String) to ByVal. Sorry I should have mentioned this before....

@ghost
Copy link
Author

ghost commented Jan 1, 2022

@GCuser99 Thank you!

@uezo
Copy link
Owner

uezo commented Jan 10, 2022

@ezagdd Thank you for you kind post.

ExecuteScriptを直接呼び出す際のElementIDへの配慮を加えた『ExecuteScript』です。

Will you let me know what do you mean?

投稿ありがとうございます!上記、ElementIDへの配慮というのは具体的にどのような意味でしょうか?

@ghost
Copy link
Author

ghost commented Jan 10, 2022

@uezo さん、具体性のない単語で失礼しました。以下の説明でお判り頂けますか。

変更前(2021/07/20)は、ElementIdを渡していませんでした。

' Execute Script                '2021/7/4 add ishi -> 2021/07/20 chg ishi
Public Function ExecuteScript(Script As String, _
                              Optional args As Variant, _
                              Optional ByVal sessionId As String = vbNullString)
    Dim Data    As New Dictionary
    Data.Add "script", Script
    
    If VarType(args) <> vbVariant + vbArray Then    'args is Array
        args = Array()
    End If
    Data.Add "args", args

変更後(2021/9/30)は、引数に ElementId を加え ElmData を組み立てると共に javascript に渡す引数も複数可能な様に
見直したという事を、一口で「配慮」という単語で表現していました。
(ElmData辞書の内容は、Python+seleniumで確認し同じになる様にしました)

' Execute Script                '2021/7/4 add ishi -> 2021/07/20 chg ishi -> 2021/9/30 chg ishi
Public Function ExecuteScript(Script As String, _
                              Optional Scriptargs As Variant = vbNullString, _
                              Optional ElementId As String = vbNullString, _
                              Optional ByVal sessionId As String = vbNullString)
    Dim Data    As New Dictionary
    Data.Add "script", Script
    
    Dim ElmData As New Dictionary
    Dim args    As Variant
    If ElementId <> vbNullString Then
        ElmData.Add "ELEMENT", ElementId
        ElmData.Add ELEMENT_KEY, ElementId
        args = Array(ElmData)
        If VarType(Scriptargs) = vbVariant + vbArray Then    'Scriptargs is Array
            Dim i As Integer
            For i = 0 To UBound(Scriptargs)
                ReDim Preserve args(i + 1)
                args(i + 1) = Scriptargs(i)
            Next
        Else
            args = Array(ElmData, Scriptargs)
        End If
    Else
        args = Array()
    End If
    Data.Add "args", args

@uezo
Copy link
Owner

uezo commented Jan 10, 2022

@ezagdd Thank you, I understood! You mean when pass the web element as an argument, it can be used in JavaScript as a DOM object like below, right?

ExecuteScript("alert(arguments[0].value);", scriptArgs, element)  ' for example, element is a textbox

-> MessageBox will apear with the value of textbox

But, sorry, one more question. When ElementId = vbNullString, ScriptArgs will be ignored in your code. Will you tell me the intention?

ありがとうございます。本当にいつもありがとうございます。理解できました。引数として要素を渡すと、そのDOMオブジェクトをJavaScriptの中で利用できる、ということであってますでしょうか?たとえばコードのように、テキストボックスを引数として渡せば、arguments[x].valueelement.valueと等価な結果が得られると理解しました。

一点だけ追加で教えていただきたいのですが、ElementIdvbNullStringなとき、Scriptargsの状況を無視してargs = Array()としている意図は何でしょうか?Elementを渡さずとも値を渡すことはあると思います。

@ghost
Copy link
Author

ghost commented Jan 11, 2022

引数として要素を渡すと、そのDOMオブジェクトをJavaScriptの中で利用できる、ということであってますでしょうか?
⇒はい、合っています。

ElementIdvbNullStringなとき、Scriptargsの状況を無視してargs = Array()としている意図は何でしょうか?ElementIdを渡さずとも値を渡すことはあると思います。
ElementIdを渡さない場合の考慮不足です。
 ElementIdを渡さない場合のargs内容がどうあるべきかの確認を行った上でコードの見直しが必要です。
 少し時間を要すると思います。

@uezo
Copy link
Owner

uezo commented Jan 11, 2022

@ezagdd Thank you! If so, how about make ExecuteScript take scriptArguments as array of variant, and put it both normal values and elements?

Public Function ExecuteScript(ByVal script As String, Optional scriptArguments As Variant = Empty, Optional ByVal sessionId As String = vbNullString)
  :
  :
    Dim args()
    If Not IsEmpty(scriptArguments) Then
        ' Abort if scriptArguments passed but not array
        If VarType(scriptArguments) < vbArray Then
            Err.Raise 13, "WebDriver.ExecuteScript", "scriptArguments must be array"
        End If
        
        Dim i As Integer
        For i = 0 To UBound(scriptArguments)
            ReDim Preserve args(i)
            If TypeName(scriptArguments(i)) = "WebElement" Then
                ' Convert WebElement to Dictionary that can be handled by WebDriver
                Dim elem As New Dictionary
                elem.Add "ELEMENT", scriptArguments(i).ElementId_
                elem.Add ELEMENT_KEY, scriptArguments(i).ElementId_
                Set args(i) = elem
            Else
                args(i) = scriptArguments(i)
            End If
        Next
    End If
    Data.Add "args", args

Usage:

sargs = Array("liella", searchInput, "aquors")
Driver.ExecuteScript "alert(arguments[0] + ' ' + arguments[1].value + ' ' + arguments[2])", sargs

This works on my environment.

@uezo
Copy link
Owner

uezo commented Jan 15, 2022

I've just added support for JavaScript.

If you have any suggestion for additional specs please create issue or discussion.

@uezo uezo closed this as completed Jan 15, 2022
@ghost
Copy link
Author

ghost commented Jan 15, 2022

@uezo さん
scriptArgumentsArrayであることを必須とされていますが、複数の引数を渡す事は少ないと思われます。
私は、引数が一つの場合は配列でなくても良い、ただし複数渡す場合は引数数に制限が無い様に配列にしていました。

以下は、
  ①指摘頂いていたElementId未指定時への対応
  ②引数が一つの場合は配列でなくても良い
  ③arguments[0]ElementId固定(ElementIdが無い場合は空Dictionary)(利用者視点から0固定とした)
  ④scriptArgumentsarguments[1]~で固定(利用者視点から1~で固定とした)
の対応を行ったものです。
Isuue #24はクローズされていますが、この対応を行ったExecuteScriptを提案します。
なお、timeoutmsraiseはGCuser99さんの提案を組み入れてあります。

 Public Function ExecuteScript(ByVal Script As String, _
                              Optional scriptArguments As Variant = vbNullString, _
                              Optional ByVal ElementId As String = vbNullString, _
                              Optional ByVal sessionId As String = vbNullString, _
                              Optional ByVal timeOutms, _
                              Optional ByVal raise As Boolean = True)
    Dim Data As New Dictionary
    Dim ElmData As New Dictionary
    Dim args As Variant
    Dim savtimeOutms
    Dim i As Integer

    Data.Add "script", Script
    
    ' Set ElementID and Args
    If ElementId <> vbNullString Then
        ElmData.Add "ELEMENT", ElementId
        ElmData.Add ELEMENT_KEY, ElementId
    End If
    If VarType(scriptArguments) = vbVariant + vbArray Then    'Scriptargs is Array
        args = Array(ElmData)
        For i = 0 To UBound(scriptArguments)
            ReDim Preserve args(i + 1)
            args(i + 1) = scriptArguments(i)
        Next i
    Else
        If Not scriptArguments = vbNullString Then
            args = Array(ElmData, scriptArguments)
        Else
            args = Array(ElmData)
        End If
    End If
    Data.Add "args", args
    
    ' Set sessionId
    If sessionId = vbNullString Then
        Data.Add "sessionId", DefaultSessionId
    Else
        Data.Add "sessionId", sessionId
    End If
    
    If Not IsMissing(timeOutms) Then
        savtimeOutms = GetScriptTimeout(sessionId)
        If savtimeOutms <> timeOutms Then SetScriptTimeout timeOutms, sessionId
    End If
    
    Dim Resp As Dictionary
    Set Resp = Execute(CMD_W3C_EXECUTE_SCRIPT, Data, raise)
    
    'trap error if occurs   2022/1/3 ishi
    If IsResponseError(Resp) Then
        Err.raise 513, "WebDriver.ExecuteScript", GetResponseErrorMessage(Resp)
    Else
        ExecuteScript = Resp("value")
        If Not IsMissing(timeOutms) Then
            If savtimeOutms <> timeOutms Then SetScriptTimeout savtimeOutms, sessionId
        End If
    End If
End Function

 
動作確認用

Option Explicit

Sub TestforExecuteScript()
'==============================================================================
' ExecuteScript Easy Test
'==============================================================================
Dim objDrv      As WebDriver
Dim objElm      As WebElement
Dim Script      As String
Dim height      As Long
Dim scroll      As Long
Dim ArgsArray   As Variant

    'Open Browser
    Set objDrv = New WebDriver
    objDrv.Chrome "chromedriver.exe"
    objDrv.OpenBrowser

    'Navigate to URL
    objDrv.Navigate "https://gigazine.net/"
    objDrv.Wait
    
    'Alert (No Args)
    objDrv.ExecuteScript "alert('-- Element Focus Scroll --');"
    objDrv.Wait
    objDrv.AcceptAlert
    objDrv.Wait
    
    'Element Focus Scroll (Args is NoArray)
    Set objElm = objDrv.FindElement(By.ID, "calendar-datepicker")
    objElm.ExecuteScript "arguments[0].focus({'preventScroll': arguments[1]})", 0
    objDrv.Wait
    
    'Alert (No Args)
    objDrv.ExecuteScript "alert('-- Top Scroll --');"
    objDrv.Wait
    objDrv.AcceptAlert
    objDrv.Wait

    'Top Scroll (No Args)
    objDrv.ExecuteScript "window.scrollTo(0, 0);"
    objDrv.Wait
    
    'Alert (No Args)
    objDrv.ExecuteScript "alert('-- Scroll 500 --');"
    objDrv.Wait
    objDrv.AcceptAlert
    objDrv.Wait
    
    'Scroll 500 (Args is Array)
    ArgsArray = Array(0, 500)
    objDrv.ExecuteScript "window.scrollTo(arguments[1], arguments[2]);", ArgsArray  'Args Array
    objDrv.Wait
    
    'Alert (No Args)
    objDrv.ExecuteScript "alert('-- Top Scroll --');"     'No Args
    objDrv.Wait
    objDrv.AcceptAlert
    objDrv.Wait

    'Top Scroll (No Args)
    objDrv.ExecuteScript "window.scrollTo(0, 0);"
    objDrv.Wait
    
    'Alert (Args is Array)
    ArgsArray = Array("TEST", "Alert", "OK?", "CANCEL?")
    objDrv.ExecuteScript "alert('-- ' + arguments[1] + ' -- ' + arguments[2] + ' -- ' + arguments[3] + ' -- ' + arguments[4] + ' --');", ArgsArray  'Args Array
    objDrv.Wait
    objDrv.AcceptAlert
    objDrv.Wait
    
    'Alert (No Args)
    objDrv.ExecuteScript "alert('-- Top Scroll --');"
    objDrv.Wait
    objDrv.AcceptAlert
    objDrv.Wait

    'Top Scroll (No Args)
    objDrv.ExecuteScript "window.scrollTo(0, 0);"
    objDrv.Wait
    
    'Alert (No Args)
    objDrv.ExecuteScript "alert('-- Get Page Height & Scroll --');"
    objDrv.Wait
    objDrv.AcceptAlert
    objDrv.Wait
        
    'Get Page Height & Scroll (No Args)
    height = objDrv.ExecuteScript("return document.body.scrollHeight")
    objDrv.ExecuteScript "window.scrollTo(0, " & CStr(height) & ");"
    objDrv.Wait

    'Close Browser
    objDrv.CloseBrowser
    objDrv.Shutdown
    Set objDrv = Nothing
End Sub

@ghost
Copy link
Author

ghost commented Jan 15, 2022

@uezo さん
v0.1.3ReadMeExecuteScriptサンプルを拝見しました。この使い方なら利用者視点からも分かり易いです。
一方でWebDriverから使う事を前提としたMeThodでありWebElementMeThodにするのは厳しいと感じました。

@uezo
Copy link
Owner

uezo commented Jan 15, 2022

Hi @ezagdd ,

scriptArgumentsがArrayであることを必須とされていますが、複数の引数を渡す事は少ないと思われます。
私は、引数が一つの場合は配列でなくても良い、ただし複数渡す場合は引数数に制限が無い様に配列にしていました。

Agree. I recognized it as ToDo.
たしかにそうですね。次以降のアップデートで対応したいと思います!

③arguments[0]はElementId固定(ElementIdが無い場合は空Dictionary)(利用者視点から0固定とした)
④scriptArgumentsはarguments[1]~で固定(利用者視点から1~で固定とした)

I couldn't get why you want to separate ElementId from other argument values. And, we must provide the way to set multiple elements as argument.
なぜElementIdを他のscriptArgumentsと切り離した別の引数にされているのか理解できませんでした。理由を教えてもらえますでしょうか?ユーザーは複数のElementを引数として渡すこともあり、それを許容する必要があります。

WebElementのMeThodにするのは厳しいと感じました。

Will you let me know use cases that require WebElement.ExecuteScript()?
WebElement.ExecuteScript()したいユースケースに想定があれば教えていただけるとありがたいです🙏当該Elementをthisで指定したいとき?

@uezo uezo reopened this Jan 15, 2022
@ghost
Copy link
Author

ghost commented Jan 15, 2022

@uezo さん

なぜElementIdを他のscriptArgumentsと切り離した別の引数にされているのか理解できませんでした。理由を教えてもらえますでしょうか?ユーザーは複数のElementを引数として渡すこともあり、それを許容する必要があります。

Elementを引数として渡しjavascriptで処理しなければならないユースケースは私には想定できていないです。
利用者側のコーディング自由度を高めるため、という事なのだと捉えます。

WebElement.ExecuteScript()したいユースケースに想定があれば教えていただけるとありがたいです🙏当該Elementをthisで指定したいとき?

複数のElementを引数として渡すことを想定する限りWebElement.ExecuteScriptを実装してはいけないですし、以下の様な使い方もしてならずWebDriver.ExecuteScript()に書き換えるべきと認識しました。
v0.1.3で実装されたWebDriver.ExecuteScriptで仕様Fixでしたら、手持ちのWebElement.ExecuteScriptに関わるものは書き換えていこうと思います。
失礼しました。

    Set objElm = objDrv.FindElement(By.CssSelector, Selector値)
    objElm.ExecuteScript "arguments[0].focus({'preventScroll': arguments[1]})", 1   'No Scroll
    Set objElm = objDrv.FindElement(By.CssSelector, Selector値)
    objElm.ExecuteScript "arguments[0].focus({'preventScroll': arguments[1]})", 0   'Scroll

@uezo
Copy link
Owner

uezo commented Jan 15, 2022

Hi @ezagdd ,

Now I've got understood that this discussion is for adding ExecuteScript() to WebElement.

I want to lower the priority of this issue for the reasons below:

  1. Avoid implicit spec: "arguments[0] in the script is the element itself" is implicit
  2. Can't find use cases: WebElement of Python binding doesn't have execute_script() either. https://github.com/SeleniumHQ/selenium/blob/trunk/py/selenium/webdriver/remote/webelement.py

@ghost
Copy link
Author

ghost commented Jan 16, 2022

Can't find use cases: WebElement of Python binding doesn't have execute_script() either.

ありがとうございます。昨日時点で確認済です。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants