Skip to content

Commit

Permalink
version update
Browse files Browse the repository at this point in the history
WebCapabilities class:
    - Added AddLocalStateFlags method to WebCapabilities class as a shortcut for adding experimental browser flags - Chrome/Edge only [@Silver-Surfer, #63]
    - Added Error handling to SetDetachBrowser method to solve issue #82
    - Added Friend property Get CommandWindowStyle to WebDriver class for use in SetDetachBrowser error handling
WebDriver class:
    - Added SetDownloadFolder method for setting download folder w/o needing to set in capabilities - Chrome/Edge only
    - Added "Set lastElems = Nothing" to Shutdown method so that terminate event of WebDriver class fires
WebDriver/WebElement classes:
    - Added maxWaitTimeMS argument/functionality to IsDisplayed, IsSelected, and IsEnabled methods
ActiveX DLL solution:
    - Removed Err.Raise bug work-around after bug fixed in twinBASIC compiler
    twinBASIC banner (at least for now) no longer displays for 5 secs at startup
    - Added 32-bit support for >= Office 2010
Minor Code Cleanups
  • Loading branch information
GCuser99 committed Oct 23, 2023
1 parent 7ffc042 commit a77aa61
Show file tree
Hide file tree
Showing 28 changed files with 167 additions and 55 deletions.
Binary file modified dev/twinBasic/SeleniumVBA.twinproj
Binary file not shown.
Binary file not shown.
Binary file modified dev/twinBasic/no_registration/SeleniumVBA_win64.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion dev/twinBasic/no_registration/readme.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
This folder holds an example set demonstrating how the twinBasic DLL can be used without registration. THIS IS NOT THE RECOMMENDED SETUP, but just to show the possibilities....
This folder holds an example set demonstrating how the twinBASIC DLL can be used without registration. THIS IS NOT THE RECOMMENDED SETUP, but just to show the possibilities....

See Discussion https://github.com/GCuser99/SeleniumVBA/discussions/73
Binary file modified dist/SeleniumVBA.accdb
Binary file not shown.
Binary file modified dist/SeleniumVBA.xlam
Binary file not shown.
Binary file modified dist/SeleniumVBADLLSetup.exe
Binary file not shown.
4 changes: 2 additions & 2 deletions dist/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Below is a table showing the compatibility for each solution with various versio
| ---------------- | ------------- | ------------- |------------- |------------- |------------- |------------- |
|Excel Add-in|Not|32/64-bit|32/64-bit|32/64-bit|32/64-bit|32/64-bit|
|Access DB|Not|32/64-bit|32/64-bit|32/64-bit|32/64-bit|32/64-bit|
|ActiveX DLL*|Not|64-bit Only|64-bit Only|64-bit Only|64-bit Only|64-bit Only|
|ActiveX DLL*|Not|32/64-bit|32/64-bit|32/64-bit|32/64-bit|32/64-bit|

*the [twinBASIC](https://twinbasic.com) ActiveX DLL can be called from MS VBScript, as well as MS Excel and MS Access

Expand All @@ -31,7 +31,7 @@ Instructions for referencing add-in versions of SeleniumVBA from another MS Exce

### ActiveX DLL Installation:

For the [twinBASIC](https://twinbasic.com) ActiveX DLL, more detailed instructions on how to install and use the DLL will be presented during installation. The setup program, which was compiled using Inno Setup, will install and register the DLL, and copy test Excel, Access, and VBScript documents to the installation folder. After installation, be aware that when it is first called during a VBA session, SeleniumVBA will display a "twinBASIC" banner for 5 seconds. Subsequent calls during the session will not show the banner.
For the [twinBASIC](https://twinbasic.com) ActiveX DLL, more detailed instructions on how to install and use the DLL will be presented during installation. The setup program, which was compiled using Inno Setup, will install and register the DLL, and copy test Excel, Access, and VBScript documents to the installation folder.

The [twinBASIC](https://twinbasic.com) ActiveX DLL solution requires no dependencies (such as .Net Framework).

Expand Down
2 changes: 1 addition & 1 deletion src/ClassFactory.bas
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Attribute VB_Description = "This class is used for object instantiation when ref
'@ModuleDescription "This class is used for object instantiation when referencing SeleniumVBA externally from another code project"
'@folder("SeleniumVBA.Source")
' ==========================================================================
' SeleniumVBA v4.6
' SeleniumVBA v4.7
'
' A Selenium wrapper for browser automation developed for MS Office VBA
'
Expand Down
3 changes: 1 addition & 2 deletions src/WebActionChain.cls
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Attribute VB_Description = "This class is used to emulate a human interaction se
'@Exposed
'@folder("SeleniumVBA.Source")
' ==========================================================================
' SeleniumVBA v4.6
' SeleniumVBA v4.7
'
' A Selenium wrapper for browser automation developed for MS Office VBA
'
Expand Down Expand Up @@ -1189,7 +1189,6 @@ Private Function actionPointerMove(Optional ByVal x As Long = 0, Optional ByVal
elem.Add "element-6066-11e4-a52e-4f735466cecf", elementId
action.Add "origin", elem
End If
'action.Add "origin", elem

action.Add "duration", duration 'Only applicable to 'pause' and 'pointerMove'.
action.Add "x", x
Expand Down
2 changes: 1 addition & 1 deletion src/WebAlert.cls
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Attribute VB_Description = "This class is used to manage browser alerts - must b
'@Exposed
'@folder("SeleniumVBA.Source")
' ==========================================================================
' SeleniumVBA v4.6
' SeleniumVBA v4.7
'
' A Selenium wrapper for browser automation developed for MS Office VBA
'
Expand Down
60 changes: 59 additions & 1 deletion src/WebCapabilities.cls
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Attribute VB_Description = "This class is used to manage/set Selenium optional C
'@Exposed
'@folder("SeleniumVBA.Source")
' ==========================================================================
' SeleniumVBA v4.6
' SeleniumVBA v4.7
'
' A Selenium wrapper for browser automation developed for MS Office VBA
'
Expand Down Expand Up @@ -200,6 +200,8 @@ Attribute SetDetachBrowser.VB_Description = "Sets the detach option for Edge/Chr
'this sets whether browser is closed (false) or left open (true) when the driver is sent the shutdown command
Select Case browser_
Case svbaBrowser.Chrome, svbaBrowser.Edge
If Not (driver_.CommandWindowStyle = vbHide Or driver_.CommandWindowStyle = vbMinimizedNoFocus) Then _
Err.Raise 1, "WebCapabilities", "The SetDetachBrowser method is not compatible with command window style - use vbHide or vbMinimizeNoFocus."
Me.SetOption "detach", val
Case svbaBrowser.Firefox
Err.Raise 1, "WebCapabilities", "The SetDetachBrowser method is not supported by the Firefox browser."
Expand All @@ -221,6 +223,62 @@ Attribute SetDebuggerAddress.VB_Description = "Sets the Debugger Address option
End Select
End Sub

'@Description("Adds a list of experimental browser flags (edge://flags, chrome://flags). Flags must end in @0 (default), @1 (enable), or @2 (disable)")
Public Sub AddLocalStateFlags(ParamArray flagsList() As Variant)
Attribute AddLocalStateFlags.VB_Description = "Adds a list of experimental browser flags (edge://flags, chrome://flags). Flags must end in @0 (default), @1 (enable), or @2 (disable)"
Dim flags As Collection
Dim localState As New Dictionary
Dim browser As New Dictionary
Dim varry() As Variant
Dim addList() As String
Dim flag As String
varry = flagsList
addList = paramListToStringArray(varry)

If browser_ <> Chrome And browser_ <> Edge Then Err.Raise 1, , "Error in SetLocalStateFlag - only valid for Edge and Chrome browsers."

'build the enabled_labs_experiments structure if needed
If Not data_.Item("alwaysMatch")(browserOptionKey).Exists("localState") Then
browser.Add "enabled_labs_experiments", New Collection
localState.Add "browser", browser
SetOption "localState", localState
Else
If Not data_.Item("alwaysMatch")(browserOptionKey)("localState").Exists("browser") Then
browser.Add "enabled_labs_experiments", New Collection
data_.Item("alwaysMatch")(browserOptionKey)("localState").Add "browser", browser
Else
If Not data_.Item("alwaysMatch")(browserOptionKey)("localState")("browser").Exists("enabled_labs_experiments") Then
data_.Item("alwaysMatch")(browserOptionKey)("localState")("browser").Add "enabled_labs_experiments", New Collection
End If
End If
End If

'get the current flags collection
Set flags = data_.Item("alwaysMatch")(browserOptionKey)("localState")("browser")("enabled_labs_experiments")

'check if the flag already exists in the collection, and if so, remove it
Dim i As Long
Dim j As Long
For j = 1 To UBound(addList)
flag = addList(j)
For i = 1 To flags.Count
If Split(flags.Item(i), "@")(0) = Split(flag, "@")(0) Then
flags.Remove i
Exit For
End If
Next i
Next j

'add the flags
'this does not guard against user specifying same flag twice
For j = 1 To UBound(addList)
flags.Add addList(j)
Next j

'reset the modified flags collection
Set data_.Item("alwaysMatch")(browserOptionKey)("localState")("browser")("enabled_labs_experiments") = flags
End Sub

'-------------------------------------------------------------------------
' Option Argument Settings
'-------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/WebCookie.cls
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Attribute VB_Description = "This class is used to manage/modify a cookie object"
'@Exposed
'@folder("SeleniumVBA.Source")
' ==========================================================================
' SeleniumVBA v4.6
' SeleniumVBA v4.7
'
' A Selenium wrapper for browser automation developed for MS Office VBA
'
Expand Down
2 changes: 1 addition & 1 deletion src/WebCookies.cls
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Attribute VB_Description = "This class is used to manage a collection of cookie
'@Exposed
'@folder("SeleniumVBA.Source")
' ==========================================================================
' SeleniumVBA v4.6
' SeleniumVBA v4.7
'
' A Selenium wrapper for browser automation developed for MS Office VBA
'
Expand Down
88 changes: 69 additions & 19 deletions src/WebDriver.cls
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Attribute VB_Description = "This class provides the main mechanism to control/au
'@Exposed
'@folder("SeleniumVBA.Source")
' ==========================================================================
' SeleniumVBA v4.6
' SeleniumVBA v4.7
'
' A Selenium wrapper for browser automation developed for MS Office VBA
'
Expand Down Expand Up @@ -345,6 +345,10 @@ Attribute CommandWindowStyle.VB_Description = "Set the driver command window dis
appWinStyle = style
End Property

Friend Property Get CommandWindowStyle() As VbAppWinStyle
CommandWindowStyle = appWinStyle
End Property

'@Description("Start an Edge driver")
Public Sub StartEdge(Optional ByVal driverPath As String = "msedgedriver.exe", Optional ByVal localHostPort As Long, Optional ByVal enableLogging As Boolean = False, Optional ByVal logFilePath As String = ".\edge.log")
Attribute StartEdge.VB_Description = "Start an Edge driver"
Expand Down Expand Up @@ -452,6 +456,9 @@ Attribute Shutdown.VB_Description = "Shuts down all driver instances attached to
If sessionId_ <> vbNullString Then CloseBrowser
execute tCMD.CMD_SHUTDOWN
End Select

'need to set this global used by Highlight to nothing or else WebDriver class' terminate event may not fire
Set lastElems = Nothing
End Sub

'@Description("Opens browser instance with specified capabilities")
Expand Down Expand Up @@ -877,8 +884,11 @@ Attribute SendKeysToOS.VB_Description = "Sends a key sequence to the active or s
Dim filePath As String
filePath = "%TEMP%\seleniumVBAtmp" & Timer() & ".vbs"
SaveStringToFile vbs, filePath

'launch the script!
Shell "WScript """ & ResolvePath(filePath) & """ , vbNormalFocus"

'remember to clean up later on WebDriver terminate event
cleanupTempFiles = True
Else
'not running on separate thread, so use native VBA instead of VBSript
Expand Down Expand Up @@ -906,7 +916,7 @@ Attribute SendKeysToOS.VB_Description = "Sends a key sequence to the active or s
End If
Else
'no window specified so send keys to active window
'but make sure we are not sending to the IDE!!!!
'but make sure we are not sending to the IDE if debugging!!!!
If Not IsActiveWindowVBIDE Then
For i = 1 To sendPackage.Count
VBA.SendKeys sendPackage(i), False 'send the keys
Expand Down Expand Up @@ -1309,11 +1319,9 @@ Attribute DeSelectByVisibleText.VB_Description = "Deselects the dropdown option
End Sub

'@Description("Returns a boolean indicating if the dropdown option element is selected")
Public Function IsSelected(element As WebElement) As Boolean
Public Function IsSelected(element As WebElement, Optional ByVal maxWaitTimeMS As Long = 0) As Boolean
Attribute IsSelected.VB_Description = "Returns a boolean indicating if the dropdown option element is selected"
Dim data As New Dictionary
data.Add "id", element.elementId
IsSelected = execute(tCMD.CMD_IS_ELEMENT_SELECTED, data)("value")
IsSelected = waitForIsCommand(tCMD.CMD_IS_ELEMENT_SELECTED, element, maxWaitTimeMS)
End Function

'@Description("Returns a boolean indicating if the element is a multi-select dropdown")
Expand Down Expand Up @@ -1445,7 +1453,7 @@ Attribute ExecuteCDP.VB_Description = "Executes a CDP command and returns a dict
Case svbaBrowser.Chrome
package.Add "service", "goog"
Case Else
Err.Raise 1, "WebDriver", "The ExecuteCDP method can only be used with Edge and Chrome browsers."
Err.Raise 405, "WebDriver", "The ExecuteCDP method can only be used with Edge and Chrome browsers."
End Select

'execute command and then let caller parse the result, including error if occurs
Expand Down Expand Up @@ -1501,7 +1509,7 @@ Attribute SaveScreenshot.VB_Description = "Saves a screenshot of the active brow
Case svbaBrowser.Firefox
pngstr = execute(tCMD.CMD_SCREENSHOT_FULL_FF)("value")
Case svbaBrowser.IE
Err.Raise 1, "WebCapabilities", "The SaveScreenShot method with argument fullScreenShot=True is not supported by the IE browser."
Err.Raise 405, "WebCapabilities", "The SaveScreenShot method with argument fullScreenShot=True is not supported by the IE browser."
End Select
Else
If element Is Nothing Then
Expand Down Expand Up @@ -1669,19 +1677,16 @@ Attribute IsPresent.VB_Description = "Returns a boolean indicating if the elemen
End Function

'@Description("Returns a boolean indicating if the element is enabled")
Public Function IsEnabled(element As WebElement) As Boolean
Public Function IsEnabled(element As WebElement, Optional ByVal maxWaitTimeMS As Long = 0) As Boolean
Attribute IsEnabled.VB_Description = "Returns a boolean indicating if the element is enabled"
Dim data As New Dictionary
data.Add "id", element.elementId
IsEnabled = execute(tCMD.CMD_IS_ELEMENT_ENABLED, data)("value")
IsEnabled = waitForIsCommand(tCMD.CMD_IS_ELEMENT_ENABLED, element, maxWaitTimeMS)
End Function

'@Description("Returns a boolean indicating if the element is displayed")
Public Function IsDisplayed(element As WebElement) As Boolean
Public Function IsDisplayed(element As WebElement, Optional ByVal maxWaitTimeMS As Long = 0) As Boolean
Attribute IsDisplayed.VB_Description = "Returns a boolean indicating if the element is displayed"
Dim data As New Dictionary
data.Add "id", element.elementId
IsDisplayed = execute(tCMD.CMD_IS_ELEMENT_DISPLAYED, data)("value")
'see https://www.w3.org/TR/webdriver/#element-displayedness
IsDisplayed = waitForIsCommand(tCMD.CMD_IS_ELEMENT_DISPLAYED, element, maxWaitTimeMS)
End Function

'@Description("Gets the browser name")
Expand Down Expand Up @@ -2026,7 +2031,7 @@ Attribute GetSessionsInfo.VB_Description = "Returns a dictionary holding various
'since only one browser per driver is allowed, this will return a collection of one
'so lets return a more useful dictionary instead
If browser_ = svbaBrowser.Firefox Then
Err.Raise 1, "WebDriver", "GetSessionsInfo method not supported for Firefox WebDriver"
Err.Raise 405, "WebDriver", "GetSessionsInfo method not supported for Firefox WebDriver"
End If
Set GetSessionsInfo = execute(tCMD.CMD_GET_ALL_SESSIONS)("value")(1)
End Function
Expand Down Expand Up @@ -2251,7 +2256,7 @@ Attribute DeleteFiles.VB_Description = "Deletes a list of files"
Else
strlist = Split(fileList(i), ",")
For k = 0 To UBound(strlist)
On Error Resume Next 'file might not exists 'file might not exists
On Error Resume Next 'file might not exists
fso.DeleteFile WebShared.getFullLocalPath(strlist(k), defaultIOFolder_), True
On Error GoTo 0
Next k
Expand Down Expand Up @@ -2732,6 +2737,24 @@ Attribute ActiveWindow.VB_Description = "Returns the active WebWindow object"
Set ActiveWindow.WebDriver = Me
End Function

'@Description("Sets the default download folder path - for Edge and Chrome browsers only")
Public Sub SetDownloadFolder(Optional ByVal folderPath As String = ".\")
Attribute SetDownloadFolder.VB_Description = "Sets the default download folder path - for Edge and Chrome browsers only"
'redirect the download location AFTER capabilities have been set - can be called multiple times in same session!!
Dim params As New Dictionary
If browser_ = Firefox Or browser_ = IE Then
'GeckoDriver lack of support for cdp endpoint - https://groups.google.com/a/mozilla.org/g/dev-webdriver/c/DcYrCVCWMLU
Err.Raise 1, , "Error in SetDownloadFolder - this method can only be used with Edge and Chrome. Use WebCapabilities SetDownloadPrefs instead."
End If
'https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-setDownloadBehavior
params.Add "behavior", "allow" 'deny, allow, default
params.Add "downloadPath", ResolvePath(folderPath)
'Page. works but is deprecated as of 10/2023 - use Browser. once incognito issue is fixed
'https://github.com/GCuser99/SeleniumVBA/issues/87
'ExecuteCDP "Browser.setDownloadBehavior", params
ExecuteCDP "Page.setDownloadBehavior", params
End Sub

Friend Function execute(driverCommand As Variant, Optional parameters As Dictionary = Nothing, Optional ByVal raiseError As Boolean = True, Optional ByVal receiveTimeout As Long = -1) As Dictionary
Dim cmdMethod As String
Dim cmdPath As String
Expand Down Expand Up @@ -3120,7 +3143,7 @@ Private Function sanitizeHTML(ByVal str As String) As String

'This function renders html source "offline" by disabling dynamic content, while leaving the DOM tree intact.

'This following are disabled:
'The following are disabled:

'- script elements
'- url redirects
Expand Down Expand Up @@ -3588,6 +3611,33 @@ Private Function timeMStoCurrency(ByVal milliseconds As Long) As Currency
timeMStoCurrency = CCur(milliseconds) * (perSecond / 1000)
End Function

Private Function waitForIsCommand(cmd As Variant, element As WebElement, ByVal maxWaitTimeMS As Long) As Boolean
'this function used in IsDisplayed, IsEnabled, and IsSelected commands to facilitate optional max wait time
Dim timeStart As Currency
Dim timeEnd As Currency
Dim timeNow As Currency
Dim data As New Dictionary

GetTime timeStart 'in currency
'calculate time to quit in currency based on max time to wait in MS
timeEnd = timeStart + timeMStoCurrency(Max(maxWaitTimeMS, 0))
GetTime timeStart

data.Add "id", element.elementId

Do
If execute(cmd, data)("value") Then
waitForIsCommand = True
Exit Function
End If

SleepWinAPI 50 'ms
DoEvents 'yield to other processes
GetTime timeNow
Loop Until timeNow > timeEnd
waitForIsCommand = False
End Function

Private Sub Class_Terminate()
'delete temp files if they were created
If cleanupTempFiles Then DeleteFiles "%TEMP%\seleniumVBAtmp*.vbs"
Expand Down
Loading

0 comments on commit a77aa61

Please sign in to comment.