Skip to content

Commit

Permalink
Merge pull request #61 from uezo/feature/script-support
Browse files Browse the repository at this point in the history
Add support for JavaScript execution
  • Loading branch information
uezo authored Jan 15, 2022
2 parents 9459934 + da2d369 commit 2b6a627
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 10 deletions.
59 changes: 57 additions & 2 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ https://www.w3.org/TR/webdriver/
1. ツール>参照設定から `Microsoft Scripting Runtime` に参照を通してください

1. `WebDriver.cls``WebElement.cls``Capabilities.cls``JsonConverter.bas`をプロジェクトに追加してください
- 最新版 (v0.1.2): https://github.com/uezo/TinySeleniumVBA/releases/tag/v0.1.2
- 最新版 (v0.1.3): https://github.com/uezo/TinySeleniumVBA/releases/tag/v0.1.3

1. WebDriverをダウンロードしてください(ブラウザのメジャーバージョンと同じもの)
- Edge: https://developer.microsoft.com/ja-jp/microsoft-edge/tools/webdriver/
Expand Down Expand Up @@ -65,7 +65,7 @@ End Sub
```vb
' Start web driver
Dim Driver As New WebDriver
Driver.Chrome "C:\Users\uezo\Desktop\chromedriver.exe"
Driver.Chrome "C:\path\to\chromedriver.exe"

' Configure Capabilities
Dim cap As Capabilities
Expand All @@ -86,6 +86,61 @@ Driver.OpenBrowser cap
- Edge: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options


# ⚡️ JavaScriptの実行

`ExecuteScript()`を利用することで、ブラウザ上で任意のJavaScriptコードを実行することができます。

```vb
' Start web driver
Dim Driver As New WebDriver
Driver.Chrome "C:\path\to\chromedriver.exe"

' Open browser
Driver.OpenBrowser

' Navigate to Google
Driver.Navigate "https://www.google.co.jp/?q=liella"

' Show alert
Driver.ExecuteScript "alert('Hello TinySeleniumVBA')"

' === Use breakpoint to CLOSE ALERT before continue ===

' Pass argument
Driver.ExecuteScript "alert('Hello ' + arguments[0] + ' as argument')", Array("TinySeleniumVBA")

' === Use breakpoint to CLOSE ALERT before continue ===

' Pass element as argument
Dim searchInput
Set searchInput = Driver.FindElement(By.Name, "q")
Driver.ExecuteScript "alert('Hello ' + arguments[0].value + ' ' + arguments[1])", Array(searchInput, "TinySeleniumVBA")

' === CLOSE ALERT and continue ===

' Get return value from script
Dim retStr As String
retStr = Driver.ExecuteScript("return 'Value from script'")
Debug.Print retStr

' Get WebElement as return value from script
Dim firstDiv As WebElement
Set firstDiv = Driver.ExecuteScript("return document.getElementsByTagName('div')[0]")
Debug.Print firstDiv.GetText()

' Get complex structure as return value from script
Dim retArray
retArray = Driver.ExecuteScript("return [['a', '1'], {'key1': 'val1', 'key2': document.getElementsByTagName('div'), 'key3': 'val3'}]")

Debug.Print retArray(0)(0) ' a
Debug.Print retArray(0)(1) ' 1

Debug.Print retArray(1)("key1") ' val1
Debug.Print retArray(1)("key2")(0).GetText() ' Inner Text
Debug.Print retArray(1)("key2")(1).GetText() ' Inner Text
Debug.Print retArray(1)("key3") ' val3
```

# ❤️ 謝辞

[VBA-JSON](https://github.com/VBA-tools/VBA-JSON) という Tim Hall さんが開発したVBA用JSONコンバーターはHTTPクライアントを作る上でとても役に立ちました。このすばらしいライブラリは当該ライブラリのライセンスのもとでリリースに含まれています。ありがとうございます!
60 changes: 58 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ https://www.w3.org/TR/webdriver/
1. Set reference to `Microsoft Scripting Runtime`

1. Add `WebDriver.cls`, `WebElement.cls`, `Capabilities.cls` and `JsonConverter.bas` to your VBA Project
- Latest (v0.1.2): https://github.com/uezo/TinySeleniumVBA/releases/tag/v0.1.2
- Latest (v0.1.3): https://github.com/uezo/TinySeleniumVBA/releases/tag/v0.1.3

1. Download WebDriver (driver and browser should be the same version)
- Edge: https://developer.microsoft.com/ja-jp/microsoft-edge/tools/webdriver/
Expand Down Expand Up @@ -65,7 +65,7 @@ Use `Capabilities` to configure browser options. This is an example to launch br
```vb
' Start web driver
Dim Driver As New WebDriver
Driver.Chrome "C:\Users\uezo\Desktop\chromedriver.exe"
Driver.Chrome "C:\path\to\chromedriver.exe"

' Configure Capabilities
Dim cap As Capabilities
Expand All @@ -85,6 +85,62 @@ See also the sites below to understand the spec of `Capabilities` for each brows
- Chrome: https://chromedriver.chromium.org/capabilities
- Edge: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options


# ⚡️ Execute JavaScript

Use `ExecuteScript()` to execute JavaScript on the browser.

```vb
' Start web driver
Dim Driver As New WebDriver
Driver.Chrome "C:\path\to\chromedriver.exe"

' Open browser
Driver.OpenBrowser

' Navigate to Google
Driver.Navigate "https://www.google.co.jp/?q=liella"

' Show alert
Driver.ExecuteScript "alert('Hello TinySeleniumVBA')"

' === Use breakpoint to CLOSE ALERT before continue ===

' Pass argument
Driver.ExecuteScript "alert('Hello ' + arguments[0] + ' as argument')", Array("TinySeleniumVBA")

' === Use breakpoint to CLOSE ALERT before continue ===

' Pass element as argument
Dim searchInput
Set searchInput = Driver.FindElement(By.Name, "q")
Driver.ExecuteScript "alert('Hello ' + arguments[0].value + ' ' + arguments[1])", Array(searchInput, "TinySeleniumVBA")

' === CLOSE ALERT and continue ===

' Get return value from script
Dim retStr As String
retStr = Driver.ExecuteScript("return 'Value from script'")
Debug.Print retStr

' Get WebElement as return value from script
Dim firstDiv As WebElement
Set firstDiv = Driver.ExecuteScript("return document.getElementsByTagName('div')[0]")
Debug.Print firstDiv.GetText()

' Get complex structure as return value from script
Dim retArray
retArray = Driver.ExecuteScript("return [['a', '1'], {'key1': 'val1', 'key2': document.getElementsByTagName('div'), 'key3': 'val3'}]")

Debug.Print retArray(0)(0) ' a
Debug.Print retArray(0)(1) ' 1

Debug.Print retArray(1)("key1") ' val1
Debug.Print retArray(1)("key2")(0).GetText() ' Inner Text
Debug.Print retArray(1)("key2")(1).GetText() ' Inner Text
Debug.Print retArray(1)("key3") ' val3
```

# ❤️ Thanks

[VBA-JSON](https://github.com/VBA-tools/VBA-JSON) by Tim Hall, JSON converter for VBA helps me a lot to make HTTP client and this awesome library is included in the release under its license. Thank you!
60 changes: 58 additions & 2 deletions README.pt.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ https://www.w3.org/TR/webdriver/
1. No editor de VBA em referências selecione: `Microsoft Scripting Runtime`

1. Adicione os módulos`WebDriver.cls`, `WebElement.cls`, `Capabilities.cls` e `JsonConverter.bas` a seu projeto VBA
- Última versão (v0.1.2): https://github.com/uezo/TinySeleniumVBA/releases/tag/v0.1.2
- Última versão (v0.1.3): https://github.com/uezo/TinySeleniumVBA/releases/tag/v0.1.3

1. Faça o Download do WebDriver de acordo com o navegador (Aviso: o Webdriver e o navegador devem corresponder a mesma versão)
- Edge: https://developer.microsoft.com/ja-jp/microsoft-edge/tools/webdriver/
Expand Down Expand Up @@ -64,7 +64,7 @@ Utilize `Capabilities` para configurar as opções do navegador. Este é um exem
```vb
' Start web driver
Dim Driver As New WebDriver
Driver.Chrome "C:\Users\uezo\Desktop\chromedriver.exe"
Driver.Chrome "C:\path\to\chromedriver.exe"

' Configure Capabilities
Dim cap As Capabilities
Expand All @@ -84,6 +84,62 @@ Ver também os sites abaixo para compreender as especificações de `Capabilitie
- Chrome: https://chromedriver.chromium.org/capabilities
- Edge: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options


# ⚡️ Execute JavaScript

Utilize `ExecuteScript()` para executar JavaScript no browser.

```vb
' Start web driver
Dim Driver As New WebDriver
Driver.Chrome "C:\path\to\chromedriver.exe"

' Open browser
Driver.OpenBrowser

' Navigate to Google
Driver.Navigate "https://www.google.co.jp/?q=liella"

' Show alert
Driver.ExecuteScript "alert('Hello TinySeleniumVBA')"

' === Use breakpoint to CLOSE ALERT before continue ===

' Pass argument
Driver.ExecuteScript "alert('Hello ' + arguments[0] + ' as argument')", Array("TinySeleniumVBA")

' === Use breakpoint to CLOSE ALERT before continue ===

' Pass element as argument
Dim searchInput
Set searchInput = Driver.FindElement(By.Name, "q")
Driver.ExecuteScript "alert('Hello ' + arguments[0].value + ' ' + arguments[1])", Array(searchInput, "TinySeleniumVBA")

' === CLOSE ALERT and continue ===

' Get return value from script
Dim retStr As String
retStr = Driver.ExecuteScript("return 'Value from script'")
Debug.Print retStr

' Get WebElement as return value from script
Dim firstDiv As WebElement
Set firstDiv = Driver.ExecuteScript("return document.getElementsByTagName('div')[0]")
Debug.Print firstDiv.GetText()

' Get complex structure as return value from script
Dim retArray
retArray = Driver.ExecuteScript("return [['a', '1'], {'key1': 'val1', 'key2': document.getElementsByTagName('div'), 'key3': 'val3'}]")

Debug.Print retArray(0)(0) ' a
Debug.Print retArray(0)(1) ' 1

Debug.Print retArray(1)("key1") ' val1
Debug.Print retArray(1)("key2")(0).GetText() ' Inner Text
Debug.Print retArray(1)("key2")(1).GetText() ' Inner Text
Debug.Print retArray(1)("key3") ' val3
```

# ❤️ Agradecimentos

[VBA-JSON](https://github.com/VBA-tools/VBA-JSON) de Tim Hall, um conversor de JSON para VBA que auxilia muito ao fazer um cliente HTTP. Esta valiosa biblioteca está inclusa nesta versão junto com sua respectiva licença. Muito obrigado!
104 changes: 100 additions & 4 deletions WebDriver.cls
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
' TinySeleniumVBA v0.1.2
' TinySeleniumVBA v0.1.3
' A tiny Selenium wrapper written in pure VBA
'
' (c)2021 uezo
Expand Down Expand Up @@ -421,13 +421,107 @@ Public Function GetText(elementId As String, Optional ByVal sessionId As String
GetText = Execute(CMD_GET_ELEMENT_TEXT, data)
End Function

' Convert dictionary from script to dictionary (converted to web element)
Private Function ScriptDictToConvertedDict(dict As Variant, Optional ByVal sessionId As String = vbNullString) As Object
If dict.Exists(ELEMENT_KEY) Then
' Convert to WebElement
Set ScriptDictToConvertedDict = ToWebElement(dict(ELEMENT_KEY), sessionId)
' Return immediately (ignore other items if they exist)
Exit Function
End If

Dim ret As New Dictionary
Dim key
For Each key In dict
If TypeName(dict(key)) = "Collection" Then
ret(key) = ScriptCollectionToConvertedArray(dict(key))
ElseIf TypeName(dict(key)) = "Dictionary" Then
Set ret(key) = ScriptDictToConvertedDict(dict(key), sessionId)
ElseIf IsObject(dict(key)) Then
Set ret(key) = dict(key)
Else
ret(key) = dict(key)
End If
Next

Set ScriptDictToConvertedDict = ret
End Function

' Convert collection from script to array
Private Function ScriptCollectionToConvertedArray(col As Variant, Optional ByVal sessionId As String = vbNullString) As Variant()
Dim ary()
ReDim ary(col.Count - 1)
Dim i As Integer

For i = 0 To UBound(ary)
If TypeName(col(i + 1)) = "Collection" Then
ary(i) = ScriptCollectionToConvertedArray(col(i + 1))
ElseIf TypeName(col(i + 1)) = "Dictionary" Then
Set ary(i) = ScriptDictToConvertedDict(col(i + 1), sessionId)
ElseIf IsObject(col(i + 1)) Then
Set ary(i) = col(i + 1)
Else
ary(i) = col(i + 1)
End If
Next
ScriptCollectionToConvertedArray = ary
End Function

' Execute script
Public Function ExecuteScript(ByVal script As String, Optional scriptArguments As Variant = Empty, Optional ByVal sessionId As String = vbNullString)
Dim data As New Dictionary
If sessionId <> vbNullString Then
data.Add "sessionId", sessionId
End If
data.Add "script", script

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_KEY, scriptArguments(i).ElementId_
Set args(i) = elem
Else
args(i) = scriptArguments(i)
End If
Next
End If
data.Add "args", args

' Use resp temporarily to return value that varies depending on the contents of script
Dim resp
Set resp = Execute(CMD_W3C_EXECUTE_SCRIPT, data, True)

If TypeName(resp("value")) = "Collection" Then
ExecuteScript = ScriptCollectionToConvertedArray(resp("value"), sessionId)
ElseIf TypeName(resp("value")) = "Dictionary" Then
If resp("value").Exists("error") Then
Err.Raise 513, "WebDriver.ExecuteScript", JsonConverter.ConvertToJson(resp("value"))
End If
Set ExecuteScript = ScriptDictToConvertedDict(resp("value"), sessionId)
ElseIf IsObject(resp("value")) Then
Set ExecuteScript = resp("value")
Else
ExecuteScript = resp("value")
End If
End Function


' ==========================================================================
' Common functions
' ==========================================================================

' Execute driver command
Public Function Execute(driverCommand, Optional parameters As Dictionary = Nothing)
Public Function Execute(driverCommand, Optional parameters As Dictionary = Nothing, Optional asRawResponse As Boolean = False)
Dim method As String: method = driverCommand(0)
Dim path As String: path = driverCommand(1)
If parameters Is Nothing Then
Expand All @@ -452,8 +546,10 @@ Public Function Execute(driverCommand, Optional parameters As Dictionary = Nothi
Set resp = SendRequest(method, UrlBase + path, parameters)

' Return value(s)
If IsNull(resp("value")) Then
Set Execute = New Dictionary
If asRawResponse Then
Set Execute = resp
ElseIf IsNull(resp("value")) Then
Set Execute = Nothing
ElseIf TypeName(resp("value")) = "Collection" Then
Set Execute = resp("value")
ElseIf VarType(resp("value")) = vbObject Then
Expand Down

0 comments on commit 2b6a627

Please sign in to comment.