{"id":13804528,"url":"https://github.com/Xeo786/Rufaydium-Webdriver","last_synced_at":"2025-05-13T17:32:31.587Z","repository":{"id":217672530,"uuid":"744517761","full_name":"Xeo786/Rufaydium-Webdriver","owner":"Xeo786","description":null,"archived":false,"fork":false,"pushed_at":"2024-03-05T17:53:01.000Z","size":181,"stargazers_count":14,"open_issues_count":3,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-08-05T01:11:06.264Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"AutoHotkey","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Xeo786.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2024-01-17T13:15:45.000Z","updated_at":"2024-07-25T08:33:13.000Z","dependencies_parsed_at":"2024-01-17T21:47:34.270Z","dependency_job_id":null,"html_url":"https://github.com/Xeo786/Rufaydium-Webdriver","commit_stats":null,"previous_names":["xeo786/rufaydium-webdriver"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Xeo786%2FRufaydium-Webdriver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Xeo786%2FRufaydium-Webdriver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Xeo786%2FRufaydium-Webdriver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Xeo786%2FRufaydium-Webdriver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Xeo786","download_url":"https://codeload.github.com/Xeo786/Rufaydium-Webdriver/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225247892,"owners_count":17444135,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T01:00:49.435Z","updated_at":"2024-11-18T20:32:04.969Z","avatar_url":"https://github.com/Xeo786.png","language":"AutoHotkey","funding_links":["https://www.buymeacoffee.com/Xeo786"],"categories":["Libraries"],"sub_categories":["Networking"],"readme":"![alt text](https://i.ibb.co/HBPZ9Nd/Rufaydium.jpg)\n\n# Rufaydium\n\nAutoHotkey WebDriver Library to interact with browsers.\nRufaydium will automatically try to download the latest Webdriver and updates Webdriver according to browser Version while creating Webdriver Session.\n\nSupported browsers: Chrome, MS Edge, Firefox, Opera.\n\n**Forum:** https://www.autohotkey.com/boards/viewtopic.php?f=6\u0026t=102616\n\nRufaydium utilizes Rest API of W3C from https://www.w3.org/TR/webdriver2/\nand also supports Chrome Devtools Protocols same as [chrome.ahk](https://github.com/G33kDude/Chrome.ahk)\n\n## Note: \n\nNo need to install / setup Selenium, Rufaydium is AHK's Selenium and is more flexible than selenium.\n\n\n## If you want to support my work just [![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/Xeo786)\n\n## How to use\n\n```AutoHotkey\n#Include Rufaydium.ahk\n/*\n\tLoad \"chromedriver.exe\" from \"A_ScriptDir\"\n\tIn case Driver is not yet available, it will Download \"chromedriver.exe\" into \"A_ScriptDir\"\n\tbefore starting the Driver.\n*/\nChrome := new Rufaydium(\"chromedriver.exe\")\n\n\nf1::\n/*\n\tCreate new session if WebBrowser Version Matches the Webdriver Version.\n\tIt will ask to download the compatible WebDriver if not present.\n*/\nPage := Chrome.NewSession()\n; navigate to url\nPage.Navigate(\"https://www.autohotkey.com/\")\nreturn\n\nf12::\nChrome.QuitAllSessions() ; close all session \nChrome.Driver.Exit() ; then exits driver\nreturn\n```\n# New Rufaydium(DriverName,Parameters)\n`Rundriver()` Class integrated into Rufaydium.ahk that launches driver in the background where port 9515 set to default, \n\n```AutoHotkey\nChrome := new Rufaydium() ; will Download/Load Chrome driver as \"chromedriver.exe\" is default DriverName\nMSEdge := new Rufaydium(\"msedgedriver.exe\",\"--port=9516\") ; will Download/Load MS Edge driver communication port will be 9516\nFirefox := new Rufaydium(\"geckodriver.exe\") ; will Download/Load geckodriver for Firefox\nOpera := new Rufaydium(\"operadriver.exe\") ; will Download/Load operadriver\n```\nNote: \n\n1. Driver will be downloaded into A_ScriptDir and old driver will be moved to A_ScriptDir \"\\Backup\"\n2. Driver will not run if Port is occupied. Make sure to not run different drivers with the same port. i.e. trying to run Chromedriver and Edgedriver with the same port.\n\n# Driver Default port\nRufaydium now supports 4 WebDrivers and has one default port; it will not run if the Port is already in use. We need to run the driver with a separate port using Driver Parameters, or we need to exit the already running driver and run a different driver if we want to use the same port.  \nRufaydium has default ports for every driver to resolve this conflict:\n\n|Driver Name  | Ports |\n|-------------|-------|\n|chromedriver | 9515  |\n|msedgedriver | 9516  |\n|geckodriver  | 9517  |\n|operadriver  | 9518  |\n|unknownDriver | 9519  |\n|bravedriver | 9515  |\n\n\u003e note: BraveDriver Parameter will download chromedriver but utilizes a separate BraveCapabailities class specificall for Brave browser's settings.\n## Driver Parameters\nParameters are WebDriver.exe CMD arguments.  \nOptions can vary according to different drivers and we can also check these arguments\n\n```AutoHotkey\nMsgBox, % Clipboard := RunDriver.help(Driverexelocation)\n\n; Above MsgBox returns the following information if using chromedriver:\n/*\nUsage: chromedriver.exe [OPTIONS]\nOptions\n  --port=PORT                     port to listen on\n  --adb-port=PORT                 adb server port\n  --log-path=FILE                 write server log to file instead of stderr, increases log level to INFO\n  --log-level=LEVEL               set log level: ALL, DEBUG, INFO, WARNING, SEVERE, OFF\n  --verbose                       log verbosely (equivalent to --log-level=ALL)\n  --silent                        log nothing (equivalent to --log-level=OFF)\n  --append-log                    append log file instead of rewriting\n  --replayable                    (experimental) log verbosely and don't truncate long strings so that the log can be replayed.\n  --version                       print the version number and exit\n  --url-base                      base URL path prefix for commands, e.g. wd/url\n  --readable-timestamp            add readable timestamps to log\n  --enable-chrome-logs            show logs from the browser (overrides other logging options)\n  --allowed-ips=LIST              comma-separated allowlist of remote IP addresses which are allowed to connect to ChromeDriver\n  --allowed-origins=LIST          comma-separated allowlist of request origins which are allowed to connect to ChromeDriver. Using `*` to allow any host origin is dangerous!\n*/\n```\nHide / UnHide Driver CMD window\n```AutoHotKey\nChrome := new Rufaydium()\nChrome.Driver.visible := true ; will unhide\nChrome.Driver.visible := false ; will hide\n```\n## Script reloading\n\nWe can reload the script as many times as we want, but the driver will be active in the process so we can have control over all the sessions created through WebDriver so far. We can also close the Driver process, but this will cause issues as we can no longer access any session created through WebDriver. its better to use `Session.exit()` then `Chrome.Driver.Exit()`.\n\n```AutoHotkey\n; to download and Run chromeDriver.exe using port 10280\nChrome := new Rufaydium(\"chromedriver.exe\",\"--port=10280\")\n; to close driver \nChrome.Driver.Exit() \n; to close and Delete Driver.exe\nChrome.Driver.Delete() \n```\n\n## Driver Status\n```Autohotkey\nChrome := new Rufaydium()\nmsgbox, % \" Chrome.Status()\nmsgbox, % \".Build.Version : \" Chrome.Build.Version\n.    \"`n.OS Name : \"\tChrome.OS.Name \n.    \"`n.OS.Arch : \"\tChrome.OS.Arch\n.    \"`n.OS.Version : \" Chrome.OS.Version\n. \t \"`n.Message : \"\tChrome.Message\n. \t \"`n.Ready : \"\t\tChrome.Ready\n```\n\n## Driver Location\nif a Specific driver i.e. chromedriver is running already and occupying a specific port, Rufaydium will access that driver with driver i.e. chromedriver, while ignoring the given Location and Update the correction process location to Driver.Location\n\n```Autohotkey\nChrome1 := new Rufaydium(\"D:\\chromedriver.exe\",\"--port=9555\")\nChrome2 := new Rufaydium(\"E:\\chromedriver.exe\",\"--port=9555\") ;reaccess already running driver\nL1 := Chrome1.Driver.Location\nL2 := Chrome2.Driver.Location\nMsgbox, L1 \"`n\" L2 \"both location are through 1 driver process and port\"\n```\n## Handling Multiple Driver\nIt is better to create multiple session over single driver process, Rufaydium can also handle multiple driver executables.\nIn the Following example Chrome2 and chrome3 sharing same chromedriver.exe but chrome1 is run from different location and different port\n```Autohotkey\nChrome1 := new Rufaydium(A_desktop \"\\chromedriver.exe\",\"--port=9226\")\nChrome2 := new Rufaydium()\nChrome3 := new Rufaydium() ; reaccess existing driver\nmsgbox, % \"Driver 1 Name :\" Chrome1.Driver.Name\n.       \"`nDriver 1 Port :\" Chrome1.Driver.Port\n.       \"`nDriver 1 Dest :\" Chrome1.Driver.Location\n.       \"`nDriver 2 Name :\" Chrome2.Driver.Name\n.       \"`nDriver 2 Port :\" Chrome2.Driver.Port\n.       \"`nDriver 2 Dest :\" Chrome2.Driver.Location\n.       \"`nDriver 3 Name :\" Chrome2.Driver.Name\n.       \"`nDriver 3 Port :\" Chrome2.Driver.Port\n.       \"`nDriver 3 Dest :\" Chrome2.Driver.Location\n\nmsgbox, % Chrome1.status() \"`n`nPress Ok to close drive Drive from Chrome1\"\nChrome1.Driver.Exit() ; then exits driver\nmsgbox, % Chrome2.status() \"`n`nPress Ok to close drive Drive from Chrome2\"\nChrome2.Driver.Exit() ; then exits driver\n\n; Chrome3.status() \"`n`nthis will cause error as Chrome2 and Chrome3 were same Diver executable\"\n; Chrome3.Driver.Exit() ; already exited with chrome2\n```\n\n# Capabilities Class \nOne can access and use Capabilities after 'New Rufaydium()'  \nRufaydium will load Driver Capabilities according to the specified Driver.  \nMakes changes to capabilities before creating a session.\n\n```AutoHotkey\nChrome := new Rufaydium() ; will load Chrome driver with default Capabilities\nChrome.capabilities.setUserProfile(\"Default\") ; can use Default user \n\n; can change user profile Data Dir, but location: \"D:\\Profile Dir\\Profile 1\" must exist\nChrome.capabilities.setUserProfile(\"Profile 1\",\"D:\\Profile Dir\\\") \n\n; New Session will be created according to above Capabilities settings\nSession := Chrome.NewSession()\n```\n## Enable HeadlessMode\nThis will SET and GET HeadlessMode\n```AutoHotkey\nBrowser.capabilities.HeadlessMode := true\nMsgBox, % Browser.capabilities.HeadlessMode\n```\n## Enable Incognito Mode\nThis will SET and GET Incognito mode\n```AutoHotkey\nBrowser.capabilities.IncognitoMode := true\nMsgBox, % Browser.capabilities.IncognitoMode\n```\n\u003eNote after Setting ```IncognitoMode := true``` .setUserProfile() would not work\n\n## UserPrompt\n[User prompt handler](https://www.w3.org/TR/webdriver2/#dfn-user-prompt-handler) can be assigned using UserPrompt, which decides handling procedure of Browser alerts/messages\n\nFollowing parameters are allowed\n| Keyword            | State                    | Description                                                                              |\n|--------------------|--------------------------|------------------------------------------------------------------------------------------|\n| dismiss            | Dismiss state            | All Alert prompt should be dismissed.                                                    |\n| accept             | Accept state             | All Alert prompt should be accepted.                                                     |\n| dismiss and notify | Dismiss and notify state | All Alert prompt should be dismissed, and an error returned that the dialog was handled. |\n| accept and notify  | Accept and notify state  | All Alert prompt should be accepted, and an error returned that the dialog was handled.  |\n| ignore             | Ignore state             | All Alert prompt should be left to the user to handle.                                   |\n\n```AutoHotkey\nMsgBox, % Browser.capabilities.UserPrompt ; default useprompt is dismiss\nBrowser.capabilities.UserPrompt := \"ignore\"\n```\n\n## Enable CrossOriginFrame\nThis will Set and Get CrossOriginFrame access\n```AutoHotkey\nBrowser.capabilities.useCrossOriginFrame := true\nMsgBox, % Browser.capabilities.useCrossOriginFrame\n```\n## Setting / Removing Args\nCommand-line arguments to use when starting Chrome. See [here](http://peter.sh/experiments/chromium-command-line-switches/)\n```AutoHotkey\nChrome := new Rufaydium()\nChrome.capabilities.addArg(\"--headless\")\nChrome.capabilities.RemoveArg(\"--headless\")\n```\n\n## Binary\nWe can also load Chromium-based browsers, for example, the Brave browser is based on chromium and can be controlled using the ChromeDriver, SetBinary has been Merged into `NewSession(binary_location)` method\n\n## other methods\n```AutoHotkey\nChrome := new Rufaydium()\n; most of the options that are included as capabilities method are defined here https://chromedriver.chromium.org/capabilities#h.p_ID_106\nChrome.capabilities.Addextensions(extensionloaction) ; will load extensions\nChrome.capabilities.AddexcludeSwitches(\"enable-automation\") ; will load Chrome without default args\nChrome.capabilities.DebugPort(9255) ; will change port for debuggerAddress\n```\n\n## SetTimeouts\nTimeout can be define at any level/time/place, \n\n```AutoHotkey\nBrowser := new Rufaydium(driver,params)\nResolveTimeout := ConnectTimeout := SendTimeout := ReceiveTimeout := 3 * 1000\nBroswer.SetTimeouts(ResolveTimeout, ConnectTimeout, SendTimeout, ReceiveTimeout)\n```\n\u003e read about [Settimeouts](https://learn.microsoft.com/en-us/windows/win32/winhttp/iwinhttprequest-settimeouts)\n\n# Rufaydium Sessions\n## New Session\nCreate a session after Setting up capabilities.  \nWe can skip capabilities, as the session will load default Capabilities based on the Driver used. The default Capabilities should work with any Driver.  \n\nNote: In case the WebDriver version is mismatched with the browser version, Rufaydium will ask to update the driver and update the WebDriver automatically and load the new driver and create a session.  \nThis ability is supported for the Chrome and MS Edge web browsers for now.\n\n```AutoHotkey\nChrome := new Rufaydium(\"chromedriver.exe\")\nSession := Chrome.NewSession()\n```\n\n## Using WebDriver with different Browsers\nBrave uses chromedriver.exe, by simply passing Browser.exe (referred binary) into NewSession() method\n\n\n```AutoHotKey\nBrave := new Rufaydium() ; Brave browser support chromedriver.exe\n; New Session will be created using Brave browser, \nSession := Brave.NewSession(\"C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe\")\nBrave.Session() ; will always open new Brave session until we reset \nBrave.Capabilities.Resetbinary() ; reset binary to driver default\nBrave.Session() ; will create Chrome session as we have loaded Chrome driver\n```\nthis way we can load All Chromium Based browsers\n\n\n## Getting Existing Sessions\nWe can also access sessions created previously using the title or URL.\n \n```AutoHotkey\nMsgbox, % json.dump(Chrome.Sessions()) ; will return all Webdriver Sessions detail\n\nSession := Chrome.getSession(1) ; this will return with Session by number sequencing from first created to latest created and switch to Active TAB\n\nSession := Chrome.getSession(1,2) ; this will return with first session and switch Second tab, Tabs count from left to right\nSession := Chrome.getSessionByUrl(URL)\nSession2 := Chrome.getSessionByTitle(Title)\n```\n\nNote: above methods are based on `httpserver\\sessions` command which is not W3C standard. Rufaydium uses AHK's functions ReadIni, WriteIni \u0026 DeleteIni, to store and parse Session IDs by creating `ActiveSessions.ini` at `GeckoDriver location`, therefore `getSessionByUrl()` \u0026 `getSessionByTitle()` now support Firefox sessions too, this way Rufaydium can continue geckodriver Sessions, or multiple AHK scripts can control Firefox.\n\n```AutoHotkey\nFF := new Rufaydium(\"geckodriver.exe\")\nPage := FF.NewSession() ; session id will be saved to ini for access after reloading script\n```\n## Session Auto Delete\nA session created by a driver can be closed by the user, Driver takes time to respond to any command in this kind of situation because Session was not closed for the driver,\n\nSession auto-delete will delete Session for a driver when a web page is not reachable/closed by the user, this automated step will be taken on any Rufaydium's method after the web page is manually/accidentally closed to overcome driver response lag,\n\n## Session.NewTab() \u0026 Session.NewWindow()\nCreates and switches to a new tab or New Window\n```AutoHotkey\nSession.NewTab()\nSession.NewWindow()\n```\nCreates new tab and New Window without switching to it\n```AutoHotkey\nSession.NewTab(0)\nSession.NewWindow(0)\n```\n\n## Session.Title\nreturns Page title\n```AutoHotkey\nMsgBox, % Session.Title\n```\n\n## Session.HTML\nreturns Page HTML\n```AutoHotkey\nMsgBox, % Session.HTML\n```\n## Session.url\nreturn Page URL\n```AutoHotkey\nMsgBox, % Session.url\nSession.url := \"https://www.autohotkey.com/boards/posting.php?mode=edit\u0026f=6\u0026p=456008\"\n```\n\n## Session.Refresh()\nRefresh the web page and wait until it gets refreshed.\n```AutoHotkey\nSession.Refresh()\nMsgBox, Page refresh complete\n```\n\n## Session.IsLoading\nTells if the page is ready or not by Returning a Boolean, this will be helpful for [Session.CDP()](https://github.com/Xeo786/Rufaydium-Webdriver#cdp-call)\n\u003enote: this function is not W3C standard will work only with Chromedriver\n```AutoHotkey\nMsgBox, % Session.IsLoading()\n```\n## Session.Navigate(url)\nNavigates to the requested URL\n```AutoHotkey\nSession.Navigate(\"https://www.autohotkey.com/\")\n```\nMultiple url can be navigated at once\n```AutoHotkey\nTabId := Session.currentTab\nSession.Navigate(url1,url2,url3,url4,url4)\nSession.Switch(TabId) ; returned to previous tab\n```\n## Session.Back() \u0026 Session.Forward()\nhelps navigate to previous or from previous to recent the page acting like browser back and forward buttons. \n\n## SwitchTab(), SwitchbyTitle() \u0026 SwitchbyURL(), ActiveTab()\nHelp to switch between tabs.\n```AutoHotkey\nSession.SwitchTab(2) ; switch tab by number, counted from left to right\nSession.SwitchbyTitle(Title)\nSession.SwitchbyURL(url)\nSession.ActiveTab() ; Switch to active tab. Note: this does not work for firefox, right now.\n```\n\n## Session window position and location\n```AutoHotkey\n; Getting window position and location\nsessionrect := Session.Getrect()\nMsgBox, % json.dump(sessionrect)\n; set session window position and location\nSrect := Session.SetRect(20,30,500,400) ; x, y, w, h \n; error handling\nif Srect.error\n\tMsgBox, % Srect.error\n; setting rect will return rect array\nrect := Session.SetRect(1,1) ; this maximize to cover full screen and while taking care of taskbar\nMsgBox, % json.Dump(rect)\n; sometime we only want to play with x or y \nSession.x := 30\nMsgBox, % session.y\n; this also return whole rect as well ; not just height and also \nk := Session.height := A_ScreenHeight - (A_ScreenHeight * 5 / 100)\nif !k.error\n\tMsgBox, json.dump(k)\n\nSession.Maximize() ; this will Maximize session window\nwindowrect := Session.Minimize() ; this will minimize session window\nif !windowrect.error ; error handling \n\tMsgBox, % json.dump(windowrect) ; if not error return with window rect\n\n; following will turn full screen mode on\nMsgBox, % Json.Dump(Session.FullScreen()) ; return with rect, you can see x and y are zero h w are full screen sizes\n; this simply turn fullscreen mode of\nSession.Maximize()\n```\n\n## Session.Close() and Session.Exit()\nSession.Close() Close Session window\nSession.Exit() terminate Session by closing all windows.\n\n```AutoHotkey\nChrome := new Rufaydium()\nPage1 := Chrome.NewSession()\nPage1.Navigate(\"https://www.google.com/\")\nPage1.NewTab() \t; create new window / tab but Page1 session pointer will remain same \nPage1.Navigate(\"https://www.autohotkey.com/boards/viewtopic.php?t=94276\") ; navigating 2nd tab\n; Page1.close() ; will close the active window / tab\nPage1.exit() ; will close all windows / tabs will end up closing whole session \n```\n\n## Switching Between Window Tabs \u0026 Frame\nOne can Switch tabs using `Session.SwitchbyTitle(Title)` or `Session.SwitchbyURL(url=\"\")`\nbut Session remains the same If you check out the [above examples](https://github.com/Xeo786/Rufaydium-Webdriver#sessionnewtab--sessionnewwindow), I posted you would easily understand how switching Tab works.\n\nJust like Switching tabs, one can Switch to any Frame but the session pointer will remain the same.\n\n![alt text](https://i.ibb.co/PW2P9ZG/Rufaydium-Frames-Example.png)\n\nAccording to the above image, we have 1 session having three tabs\n\nExample for TAB 1\n\n```AutoHotkey\nSession.SwitchbyURL(tab1url) ; to switch to TAB 1\n; tab 1 has total 3 Frame\nMsgBox, % Session.FramesLength() ; this will return Frame quantity 2 from Main frame \nSession.Frame(0) ; switching to frame A\nSession.getElementByID(someid) ; this will get element from frame A\n; now we cannot switch to frame B directly we need to go to main frame / main page\nSession.ParentFrame() ; switch back to parent frame\nSession.Frame(1) ; switching to frame B\nSession.getElementByID(someid) ; this will get element from frame B\n; frame B also has a nested frame we can switch to frame BA because its inside frame B\nSession.Frame(0) ; switching to frame BA\nSession.getElementByID(someid) ; this will get element from frame BA\nSession.ParentFrame() ; switch back to Frame B\nSession.ParentFrame() ; switch back to Main Page / Main frame\n```\n\nExample for TAB 2\n\n```AutoHotkey\nSession.SwitchbyURL(tab2url) ; to switch to TAB 2\n; tab 1 also has total 3 frames\nMsgBox, % Session.FramesLength() ; this will return Frame quantity 3\nSession.Frame(0) ; switching to frame X\nSession.ParentFrame() ; switch back to Main Page / Main frame\nSession.Frame(1) ; switching to frame Y\nSession.ParentFrame() ; switch back to Main Page / Main frame\nSession.Frame(2) ; switching to frame Z\nSession.ParentFrame() ; switch back to Main Page / Main frame\n```\n\nExample for TAB 3\n\n```AutoHotkey\nSession.SwitchbyURL(tab3url) ; to switch to TAB 3\nMsgBox, % Session.FramesLength() ; this will return Frame quantity which is Zero because TAB 3 has no frame\n```\n\u003eNote: Switching frame would not work for [Session.CDP](https://github.com/Xeo786/Rufaydium-Webdriver#cdpframes)\n\n## Error Handling\nError Handling works with all methods, except methods that return an Element pointer Few common functionalities\n\n## Accessing Element / Elements\nThe following methods return with an element pointer.\n```AutoHotkey\nElement := Session.getElementByID(id)\nElement := Session.QuerySelector(Path)\nElement := Session.QuerySelectorAll(Path)\nElement := Session.getElementsbyClassName(Class)\nElement := Session.getElementsbyName(Name) \nElement := Session.getElementsbyTagName(TagName)\nElement := Session.getElementsbyXpath(xPath)\n```\nGetting element(s) from the element Just like DOM\n```AutoHotkey\nelement := Session.querySelector(\".Someclass\")\nChildElements := element.querySelectorAll(\"#someID\")\n```\nGetting Parent and Child elements\n```AutoHotkey\ne := Page.QuerySelector(\"#keywords\")\nparentelement := e.parentElement\nfor n, child in parentelement.children\n\tmsgbox, % \"index: \" n \"`nTagName: \" child.tagname\n```\n\nAbove methods are based on `.findelement()`/`.findelements()`\n```AutoHotkey\nSession.findelement(by.selector,\"selectorparameter\") \nSession.findelements(by.selector,\"selectorparameter\") \n```\nWe can check the element's length\n```AutoHotKey\nelements := Session.querySelectorAll(Path)\nMsgBox, % elements.count()\n```\n\nSee [accessing table](https://github.com/Xeo786/Rufaydium-Webdriver#accessing-tables)\n\n## by Class\n\n```AutoHotkey\nClass by\n{\n\tstatic selector := \"css selector\"\n\tstatic Linktext := \"link text\"\n\tstatic Plinktext := \"partial link text\"\n\tstatic TagName := \"tag name\"\n\tstatic XPath\t:= \"xpath\"\n}\n```\n\n## Accessing Tables\n\nThere are many ways to access the table you can use the JavaScript function to extract `Session.ExecuteSync(JS)` or `Session.CDP.Evaluate(JS)`\nbut an easy and simple way is to utilize AHK `for` loops. Looping through the table is a little bit slow because one Rufaydium step consists of 3 steps\n\n1) `Json.Dump()` \n2) `WinHTTP Request` \n3) `Json.load()` \n\nLooping through tables takes lots of steps, so it's better to use `Session.ExecuteSync(JS)` to read huge tables and do it much faster if we just want to extract table data and do not have to interact with tables \n\n\u003eNote: Following method will only works when InnerText return with tabs and line breaks\n```AutoHotkey\n; reading thousand rows lighting fast\nTable := Session.QuerySelectorAll(\"table\")[1].innerText\nTablearray := []\nfor r, row in StrSplit(Table,\"`n\") \n{\n\tfor c, cell in StrSplit(row,\"`t\")\n\t{\n\t\t;MsgBox, % \"Row: \" r \" Col:\" C \"`nText:\" cell\n\t\tTablearray[r,c] := cell\n\t}\n}\nMsgBox, % Tablearray[1,5]\n```\n\n## Session.ActiveElement()\nreturns handle for focused/active element, this function can also act as a bridge between Session.CDP and Session.Basic\n```AutoHotkey\nCDPelement.focus()\nelement := Session.ActiveElement() ; now we have access of element which we previously focused using CDP\n```\n\n## Handling Session alerts popup messages\n```AutoHotkey\nSession.Alert(\"GET\") ; getting text from pop up msg\nSession.Alert(\"accept\") ; pressing OK / accept pop up msg\nSession.Alert(\"dismiss\") ; pressing cancel / dismiss pop up msg\nSession.Alert(\"Send\",\"some text\")  ; sending a Alert / pop up msg \n```\n\n## Tacking Screen Shots accept only png file format\n```AutoHotkey\nSession.Screenshot(\"picture location.png\") ; will save PNG to A_ScriptDir\nSession.Screenshot(a_desktop \"\\picture location.png\") ; will save PNG to a_desktop\nSession.CaptureFullSizeScreenShot(a_desktop \"\\fullPage.png\") ; will save full page screenshot\n```\n\n# PDF printing \nWebDriver only Supports headless mode printing. but Rufaydium now supports Headful mode printing thanks to \"wkhtmltopdf\"\nRufaydium will ask to download and install [wkhtmltopdf](https://wkhtmltopdf.org/), if wkhtmltopdf is not available in windows, \n\u003eplease follow [terms and condition](https://github.com/wkhtmltopdf/wkhtmltopdf/blob/master/LICENSE) from wkhtmltopdf\n## Printing pdf with wkhtmltopdf\n`Print()` Method is same but defining Printing Options is not mandatory and PrintOptions class can also be used with wkhtmltopdf.\n```AutoHotkey\nSession.print(PDFlocation,PrintOptions.A4_Default) ; see Class PrintOptions\nSession.print(PDFlocation) ; no need for print options\n```\n[Wkhtmltopdf command-line](https://wkhtmltopdf.org/usage/wkhtmltopdf.txt) parameters as Options for advanced printing\n```AutoHotkey\nparams := \"--zoom 2 --margin-bottom 0 --margin-left 0 --margin-right 0 --margin-top 0 --page-height 0\"\nSession.print(PDFlocation,params)\n```\n\u003e Note: Printing PDF from nested frame is a bit tricky but see [example](https://www.autohotkey.com/boards/viewtopic.php?f=6\u0026t=102616\u0026p=469037#p469037)\n## Headless Mode Printing\nfor Headless mode printing, we need to describe PrintOptions which is mandatory see the following example\n```AutoHotkey\nSession.print(PDFlocation,PrintOptions.A4_Default) ; see Class PrintOptions\nSession.print(PDFlocation,{\"\":\"\"}) ; for default print options\n```\n\n## Class PrintOptions\nPrintOptions to make custom PrintOptions\n```AutoHotkey\nClass PrintOptions ; https://www.w3.org/TR/webdriver2/#print\n{\n\tstatic A4_Default =\n\t( LTrim Join\n\t{\n \t\"page\":{\n \t\t\"width\": 50,\n \t\t\"height\": 60\n\t},\n \t\"margin\":{\n \t\t\"top\": 2,\n \t\t\"bottom\": 2,\n \t\t\"left\": 2,\n \t\t\"right\": 2\n\t},\n \t\"scale\": 1,\n \t\"orientation\": \"portrait\",\n\t\"shrinkToFit\": json.true,\n \t\"background\": json.true\n\t}\n\t)\n}\n```\n\n## Session inputs events\n\n```AutoHotkey\nSession.move(x,y) ;move mouse pointer to location\nSession.click() ; sending left click on moved location ; [button: 0(left) | 1(middle) | 2(right)]\nSession.DoubleClick() ; sending double left click on moved location ; [button: 0(left) | 1(middle) | 2(right)]\nSession.MBDown() ; sending mouse left click down on moved location ; [button: 0(left) | 1(middle) | 2(right)]\nSession.MBup() ; sending mouse left click up on moved location ; [button: 0(left) | 1(middle) | 2(right)]\n; now you can understand how to drag and drop stuff  read about element location rect and size further down below \n```\n\n## Session Cookies\n\n```AutoHotkey\nSession.GetCookies() ; return with object array of cookies you need to parse then and understand \nSession.GetCookieName(Name) ; return with cookie with Name haven't tested it \nSession.AddCookie(CookieObj) ; will add cookie idk request parameters for adding cookies\n```\nUse JSON.Dump() to determine the cookie's attributes.\n```AutoHotkey\nMsgbox, %  JSON.Dump(Session.GetCookies())\n/*\n[{\"domain\": \".autohotkey.com\", \"expiry\": 1654584141, \"httpOnly\": 0, \"name\": \"_gat_gtag_UA_5170375_17\", \"path\": \"/\", \"secure\": 0, \"value\": \"1\"}, \n{\"domain\": \".autohotkey.com\", \"expiry\": 1654670481, \"httpOnly\": 0, \"name\": \"_gid\", \"path\": \"/\", \"secure\": 0, \"value\": \"GA1.2.1414453342.1654584081\"}, \n{\"domain\": \".autohotkey.com\", \"expiry\": 1717656081, \"httpOnly\": 0, \"name\": \"_ga\", \"path\": \"/\", \"secure\": 0, \"value\": \"GA1.2.1530957962.1654584081\"}]\n*/\n```\nAn example of retrieving all cookies. Some results may return blank if the cookie doesn't have that attribute.\n\n```AutoHotkey\ncookies := Session.GetCookies() ; https://developer.chrome.com/docs/extensions/reference/cookies/#type-Cookie\nLoop % cookies.Length()\n{\n    MsgBox, % cookies[A_Index].Domain\t; .autohotkey.com\t\n    MsgBox, % cookies[A_Index].Expiry\t; 1654584321\t\n    MsgBox, % cookies[A_Index].HostOnly ; \n    MsgBox, % cookies[A_Index].HttpOnly ; 0\n    MsgBox, % cookies[A_Index].Name\t; _gat_gtag_UA_1234567_89\n    MsgBox, % cookies[A_Index].Path\t; /\n    MsgBox, % cookies[A_Index].SameSite\t;    \n    MsgBox, % cookies[A_Index].Secure   ; 0\n    MsgBox, % cookies[A_Index].Session  ; \n    MsgBox, % cookies[A_Index].StoreId  ; \n    MsgBox, % cookies[A_Index].Value    ; 1\n}\n```\nAn example of retrieving a single cookie by name.\n```AutoHotkey\nvar := Session.GetCookieName(\"CFID\")\nMsgBox, % var.Domain \" | \" var.Expiry \" | \" var.Value ; etc.\n```\n\n# WDElement\nAvailable web driver Elements methods.\n\n```AutoHotkey\nElement.Name() ; will return tagname\nElement.Rect() ; will return position and size\nElement.enabled() ; will return Boolean true for enabled or false disabled \nElement.Selected() ; will return Boolean true for Selected or false not selected this will come handy for dropdown lists or combo list selecting options\nElement.Displayed() ; will return Boolean true for visible element / false for invisible element\n\n; inputs and event triggers \nElement.Submit() ; this will trigger existing event(s)\nElement.SendKey(\"text string \" . key.class ) ; this convert text and will send key event to element and see Key.class for special keys \nElement.SendKey(key.ctrl \"a\" key.delete) ; this will clear text content in edit box by simply doing Ctrl + A and  delete\nElement.Click() ; sent simple click\nElement.Move() ; move mouse pointer to that element it will help drag drop stuff see session.click and session.move \nElement.onchange() ; to dispatch onchange() event\nElement.clear() ; will clear selected item / uploaded file or content text \n\n; Attribs properties \u0026 CSS\nElement.GetAttribute(Name) ; return with required attribute\nElement.GetProperty(Name) ; return with required Property\nElement.GetCSS(Name) ; return with CSS\n\n; element Shadow\nElement.Shadow() ; return with shadow element detail actually I going to add functionality to access shadow elements in future\n; first I need to learn about them\n\nElement.Sendkey(StrReplace(filelocation,\"\\\",\"/\")) ; if Element is input element than file location can be set using SendKey()\n; click on upload button now initiate fileupload, after setting file location\n```\nGetting web driver Elements information.\n```AutoHotkey\ne := Page.querySelector(selector) ; getting element \nmsgbox % e.innerText\nmsgbox % \"TagName: \" e.TagName \"`nName: \" e.Name \"`nID: \" e.id \"`nTitle: \" e.Title \"`nClass: \" e.Class \"`nValue: \" e.value\nmsgbox, % e.InnerHTML\nmsgbox, % e.outerHTML\nmsgbox, % \"href: \" e.href \"`nSrc: \" e.src\n```\nSetting / Changing Web Driver Elements information.\n```AutoHotkey\ne.Name := \"abcd\"\ne.id := \"Mywords\"\ne.Title := \"My Title\"\ne.Class := \"My Class\"\ne.value := \"My Value\"\nnewhtml = \u003cbutton name=\"Rufaydium\" id=\"MyButton\" \u003eRufaydium\u003c/button\u003e\ne.outerHTML := newhtml \ne.InnerHTML := newhtml \ne.href := url\ne.src := url\n```\n\u003eNote: Element manipulation is not available for Rufaydium basic, versions less than 1.6.3\n## Shadow Elements\nShadow elements can easily be accessed using `element.shadow()`.\nThe following example will navigate to the Chrome extensions page and enables Developer mode\n```AutoHotKey\nChrome := new Rufaydium()\nPage := Chrome.getSessionByUrl(\"chrome://extensions\")\nif !isobject(page)\n{\n\tPage := Chrome.NewSession()\n\tPage.Navigate(\"chrome://extensions\")\n}\npage.QuerySelector(\"extensions-manager\").shadow().QuerySelector(\"extensions-toolbar\").shadow().getelementbyid(\"devMode\").click()\n```\n## Key.Class\n\n```AutoHotkey\nClass Key\n{\n\tstatic Unidentified := \"\\uE000\"\n\tstatic Cancel:= \"\\uE001\"\n\tstatic Help:= \"\\uE002\"\n\tstatic Backspace:= \"\\uE003\"\n\tstatic Tab:= \"\\uE004\"\n\tstatic Clear:= \"\\uE005\"\n\tstatic Return:= \"\\uE006\"\n\tstatic Enter:= \"\\uE007\"\n\tstatic Shift:= \"\\uE008\"\n\tstatic Control:= \"\\uE009\"\n\tstatic Ctrl:= \"\\uE009\"\n\tstatic Alt:= \"\\uE00A\"\n\tstatic Pause:= \"\\uE00B\"\n\tstatic Escape:= \"\\uE00C\"\n\tstatic Space:= \"\\uE00D\"\n\tstatic PageUp:= \"\\uE00E\"\n\tstatic PageDown:= \"\\uE00F\"\n\tstatic End:= \"\\uE010\"\n\tstatic Home:= \"\\uE011\"\n\tstatic ArrowLeft:= \"\\uE012\"\n\tstatic ArrowUp:= \"\\uE013\"\n\tstatic ArrowRight:= \"\\uE014\"\n\tstatic ArrowDown:= \"\\uE015\"\n\tstatic Insert:= \"\\uE016\"\n\tstatic Delete:= \"\\uE017\"\n\tstatic F1:= \"\\uE031\"\n\tstatic F2:= \"\\uE032\"\n\tstatic F3:= \"\\uE033\"\n\tstatic F4:= \"\\uE034\"\n\tstatic F5:= \"\\uE035\"\n\tstatic F6:= \"\\uE036\"\n\tstatic F7:= \"\\uE037\"\n\tstatic F8:= \"\\uE038\"\n\tstatic F9:= \"\\uE039\"\n\tstatic F10:= \"\\uE03A\"\n\tstatic F11:= \"\\uE03B\"\n\tstatic F12:= \"\\uE03C\"\n\tstatic Meta:= \"\\uE03D\"\n\tstatic ZenkakuHankaku:= \"\\uE040\"\t\n}\n```\n# Session.Actions()\nWe can interact with a page using `Actions(interactions*)` method, interactions are generated using [Mouse](https://github.com/Xeo786/Rufaydium-Webdriver#mouse-class), [Scroll](https://github.com/Xeo786/Rufaydium-Webdriver#scroll-class) [Keyboard](https://github.com/Xeo786/Rufaydium-Webdriver#keyboard-class) Classes based on [Actions](https://github.com/Xeo786/Rufaydium-Webdriver#actions-class) Class. Sending Empty Actions() method would release/stop ongoing action.\n```AutoHotKey\nSession.Actions(Interaction1,Interaction2,interaction3) ; read Action class for Interactions\n\nSession.Actions() ; stop onging action\n```\n# Actions Class\nAction class that help generating Webdriver Actions Payload for Session.Actions() method, extends from [Mouse](https://github.com/Xeo786/Rufaydium-Webdriver#mouse-class), [Scroll](https://github.com/Xeo786/Rufaydium-Webdriver#scroll-class) [Keyboard](https://github.com/Xeo786/Rufaydium-Webdriver#keyboard-class) Classes (hereinafter referred to as \"interaction/interactions\" ), action payloads should be casesensitive and has specific parameters for concerning \"pointerType\", so these classes not only helps generating them, but also make them easy to understand.\n\nFollowing methods inherited to Mouse, Scroll and Keyboard Classes, generate a interaction Objects that later translated to Webdriver Actions payload, hereinafter referred to as \"Event/Events creations\" \n\n`Pause(duration)` create event of \"pause\" to cause delay between interactions, where default 'duration' is 100\n\n`cancel()` create 'pointerCancel' event\n\n`Clear()` resets interaction by deleting all delete Events\n\u003e note: One interaction Class Object has multiple events\n## Mouse Class\n\nMouse Class generates event/interaction Objects 'Type' \"pointer\" that later translated to Webdriver Actions payload when submitted as parameters to Session.Actions().\n\n`interaction := New mouse(pointerType)` accepts 'pointerType' as parameter which can be \"mouse\", \"pen\", or \"touch\", where default pointerType is mouse, return  interaction Class object.\n\n`mouse.Clear()` resets interaction by deleting all delete Events.\n\n`mouse.cancel()` create 'pointerCancel' event, which act like mouse not over document.\n\n`mouse.press(Button)` create a payload object for \"pointerDown\", accepts \"Button\" parameter 0(left), 1(middle), or 2(right) mouse button, empty parameter considered 0 to autohotkey results setting left mouse button default.\n\n`mouse.Release(Button)` create a payload object for \"pointerUp\", accepts \"Button\" parameter 0(left), 1(middle), or 2(right) mouse button, empty parameter considered 0 to autohotkey results setting left mouse button default.\n\n`mouse.Move(x,y,duration,width,height,pressure,tangentialPressure,tiltX,tiltY,twist,altitudeAngle,azimuthAngle,origin)` will move mouse pointer to 'x' 'y' direction, moveing taking time as 'duration', \npointer size can be define as 'width' 'height' which is optional, \n\nmove can be tweaked for button/touch 'pressure' 'tangentialPressure' 'tiltX','tiltY','twist','altitudeAngle','azimuthAngle' by using these respective parameters, which are also optional. \n\n\"origin\" can be  \"viewport\" or \"pointer\"\n\nDefault parameters for move:\n| Parameters | Ports |\n|-------------|-------|\n|x|0|\n|y|0|\n|duration|10|\n|width|0|\n|height|0|\n|pressure|0|\n|tangentialPressure|0|\n|tiltX|0|\n|tiltY|0|\n|twist|0|\n|altitudeAngle|0|\n|azimuthAngle|0|\n|origin|\"viewport\"|\n\n\n`mouse.click(button,x,y,duration)` click generates for serialized objects following methods already defined above, and will be translated to JSON payload and executed one by one from first to last creation.\n```AutoHotKey\n        mouse.move(x,y,0)\n        mouse.press(button,duration)\n        mouse.Pause(500)\n        mouse.release(button,duration)\n```\n\nMouse Interaction and event example\n```AutoHotKey\nMouseEvent := new mouse() ; Setting pointerType \"mouse\"\nMouseEvent.press() ; 0(left) | 1(middle) | 2(right)\nMouseEvent.move(288,258,10)\nMouseEvent.release()\nSession.Actions(MouseEvent)\nreturn\n```\n\n## Scroll Class\nScroll Class generates event/interaction Objects 'Type' \"wheel\" that later translated to Webdriver Actions payload when submitted as parameters to Session.Actions().\n\n`interaction := New Scroll(pointerType)` accepts 'pointerType' as parameter which can be \"mouse\", \"pen\", or \"touch\", where default pointerType is mouse, return interaction Class object.\n\n`interaction.Clear()` resets interaction by deleting all delete Events.\n\n`interaction.Scroll(deltaX,deltaY,x,y,duration,origin)` navigates vertical horizontal scroll on webpage's document view. \nIt performs a scroll given duration, x, y, target delta x, target delta y, current delta x and current delta y:\n\nDefault parameters for Scroll method:\n| Parameters | Ports |\n|-------------|-------|\n|deltaX|0|\n|deltaY|0|\n|x|0|\n|y|0|\n|duration|10|\n|origin|\"viewport\"|\n\nFollowing Methods utilized ```.Scroll(s)``` to perform scroll up down left right, where 's' is Scrolling value from the calculated from the exiting position, default value for 's' is 50 \n\n`interaction.ScrollUP(s)`\n\n`interaction.ScrollDown(s)`\n\n`interaction.ScrollLeft(s)`\n\n`interaction.ScrollRight(s)`\n\n## Keyboard Class\nKeyboard Class generates event/interaction Objects 'Type' \"key\" that later translated to Webdriver Actions payload when submitted as parameters to Session.Actions().\n\n```KeyInterAction := New Keyboard()``` return interaction Class object. does not required any parameter\n\n```Keyboard.Clear()``` resets interaction by deleting all delete Events.\n\n```Keyboard.keyUp(key)``` create a payload object for \"keyUp\", required \"key\" parameter as key \"Value\"\n\n```Keyboard.keyDown(key)``` create a payload object for \"keyDown\", required \"key\" parameter as key \"Value\"\n\n```Keyboard.SendKey(keys)``` utilizes 'keyUp()' and 'keyDown()' methods simultaneously to send keystrokes, required Keys string parameter, its recommended to use `Element.Sendkey()` to mimic keystrokes on element or `WDElement.value` to set and Get element value.\n\n\u003cdetails\u003e\n  \u003csummary\u003eInteraction Examples\u003c/summary\u003e\n\n```autohotkey\n#Include, %A_ScriptDir%\\..\\Rufaydium-Webdriver\n#include Rufaydium.ahk \ngoto, TestKeyboard ; change lable here\nreturn\n\nclickTest:\nURL := \"https://quickdraw.withgoogle.com\"\npage := GetRufaydium(URL) ; run/access  chrome  browser\n\nMI := new mouse() ; MI = mouse interaction\n;MI.click(0, 400, 400)\n;MI.click(0, 200, 300)\n\nMI.press()\nMI.move(288,258,10)\nMI.release()\nMI.press()\nMI.move(391,181,10)\nMI.release()\nMI.press()\nMI.move(493,258,10)\nMI.release()\nMI.press()\nMI.move(454,358,10)\nMI.release()\nMI.press()\nMI.move(328,358,10)\nMI.release()\nMI.press()\nMI.move(288,258,10)\nMI.release()\nMI.press()\nMI.release()\nmsgbox, move drawing window and click ok to draw\nx := page.actions(MI)\nreturn\n\nScrollTest:\nURL :=  \"https://www.autohotkey.com/boards/\"\npage := GetRufaydium(URL) ; run/access  chrome  browser\nmsgbox, % please arrow up and Down keys to scroll\nreturn\n\ndown::\npage.scrollDown() ; it utilizes Scroll class\nreturn\n\nup::\npage.scrollup() ; ; it utilizes Scroll class\nreturn\n\nTestKeyboard:\nURL :=  \"https://www.autohotkey.com/boards/\"\npage := GetRufaydium(URL) ; run/access  chrome  browser\ne := Page.querySelector(\"#keywords\") ; getting elemenet \ne.focus() ; focusing element so we can see keystrokes interaction\npage.sendkey(\"aBcd\") ; session.sendkey() uses Keyboard Class\npage.sendkey(\"xyZ\")\nreturn\n\n; GetRufaydium(URL) gets existing session  \n; stops us creatting multiple sessions again and again \n; make sure do not manually close driver / chrome.driver.exit()\n; by Xeo786\nGetRufaydium(URL)\n{\n\t; get chrome driver / runs chrome driver if not running, download driver if available in A_ScriptDir\n\t; Run Chrome Driver with default parameters and loads deafult capabilities\n\tChrome := new Rufaydium() \n\tPage := Chrome.getSessionByUrl(URL) ; check page (created by driver) if already exist \n\tif !isobject(page) ; checcking if Session with url exist\n\t{\n\t\tPage := Chrome.getSession(1,1) ; try getting first session first tab\n\t\tif isobject(page) ; if exist \n\t\t\tPage.NewTab() ; create new tab instead new session\n\t\telse ; if does not exist \n\t\t\tPage := Chrome.NewSession() ; create new session ; Page.Exit() if any session manually closed by user which causes lag\n\t\tPage.Navigate(URL) ; navigate\t\t\n\t}\n\treturn page \n}\n```\n\u003c/details\u003e\n\n# Await\n\nRufaydium Basic will wait for any task/change to get completed, and then execute the next line but any task executed through CDP `Session.CDP` wouldn't wait, therefore we need to use `Session.CDP.WaitForLoad()`\n\nWaiting of webpage is based on document ready state https://www.w3schools.com/jsref/prop_doc_readystate.asp\nbut there are web pages that keep loading and unloading elements and stuff while their ready state remains `complete`, \nIn this kind of situation Rufaydium Basic and Rufaydium CDP would simply wait through error or if an element in question is not available or element visibility or displayed/enabled stats element, `displayed()`, `element.enabled()`, we can use these tricks to make AutoHotkey wait, \nfor example, We have click button and this would load element with tag name button.\n\n```AutoHotkey\nwhile !IsObject(button) ; \n{\n   sleep, 200\n   ; getting element do not support error handling for now but they do return with element object if found and empty when find nothing\n   button := Session.QuerySelector(\"button\") \n}\nh := button.innerText\nwhile h.error\n{\n    h := button.innerText ; but element.methods support error handling\n    sleep, 200\n}\nMsgBox, % \"innerText\" h ; otherwise h has innertext\nButton.click()\n```\n## Session.CDP\nSession.CDP has access to Chrome Devtools protocols,\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample\u003c/summary\u003e\n\n```AutoHotkey\nChromeDriver := A_ScriptDir \"\\chromedriver.exe\"\n; in case driver is already running it will get access driver which is already running\nDriver := new RunDriver(ChromeDriver) \nChrome := new Rufaydium(Driver)\nPage := Chrome.getSessionByUrl(Webpage) ; getting session\n\nif !isobject(Page)\n{\n\tMsgBox, no session found\n\treturn\n}\n\n; Page.CDP.Document()\t; no longer needed\ninput := Page.CDP.QuerySelector(\".mb-2\")\nMsgBox, % input.innerText\nfor k , tag in  Page.cdp.QuerySelectorAll(\"input\") ; full all input boxes with their ids\n{\n\ttag.sendKey(tag.id)\n}\n\n```\n\u003c/details\u003e\n\n\u003eNote: Firefox / Geckodriver session does not support Session.CDP (Chrome Devtools Protocols) as Firefox has its Remote protocols, which will be added soon as Session.FRP, Firefox Remote Protocols\n\n# CDP.Document()\nCDP.Document() is DEPRECATED is no longer required as Rufaydium CDP has developed reliable access to frame\n\n# CDP functionalities\n```AutoHotkey\nSession.CDP.navigate(url) ; navigate to url\nSession.CDP.WaitForLoad() ; unlike Session.methods() CDP does not support await\n\n; getting element\nelement := Session.CDP.querySelector(selector) \nelement := Session.CDP.getElementByID(ID)\n; getting array or elements\nelements := Session.CDP.querySelectorAll(selector) \nelements := Session.CDP.getElementsbyClassName(Class)\nelements := Session.CDP.getElementsbyName(Tagename)\n\n/* getting element by JS function \n1) GetelementbyJS() can only be used on Document like Document.GetelementbyJS(JS), yes it will work on element \n   but it would consider document as base node / pointer\n2) The JS should return with element or array of elements i.e. GetelementbyJS(\"document.querySelectorAll('input')\")\nif you want to pass function and want use results from it then you can pass your function which should return with \n   one element or array of elements like this\n3) you can use GetelementbyJS(js).value := var and GetelementbyJS(js)[].value := var it totally depends on you \n   JavaScript what you are passing,\n4) you can't do something like this GetelementbyJS(\"document.querySelector('input').value = '1234'\") there is \n   CDP.Evaluate() for that\n5) What I think GetelementbyJS() is slow we should use DOM.querySelector for fast results but JavaScript users \n   would understand that why I have made GetelementbyJS(), in some scenarios JS get results more faster, \n   like above I mentioned below passing JS custom function using Evaluate,\n*/\nelement := Session.CDP.GetelementbyJS(\"JSfunc()\") ; JS funct\n\n; get element by location\n; this method does not reriued Session.CDP.Document()\nelement := Session.CDP.getelementbyLocation(x,y)\n```\n# CDP.Element\nFollowing methods only applicable to element(s) return from CDP \n```AutoHotkey\nCDP_element.getBoxModel()\t; with Json array of element coord margins and paddings detail\nCDP_element.getNodeQuads()\t; quads are x immediately followed by y for each point, points clock-wise\n\nval := CDP_element.value\t; get value\nCDP_element.value := \"abcd\"\t; set value\n\neleClass := CDP_element.class\t; get Class\nCDP_element.class := \"abcd\"\t; set Class\n\neleID := CDP_element.id\t\t; get id\nCDP_element.id := \"abcd\"\t; set id\n\ntext := CDP_element.innerText\t; get innerText\nCDP_element.innerText := \"abcd\"\t; set innerText\n\ntext := CDP_element.textContent\t; get textContent\n\nhtml := CDP_element.OuterHTML\t; get html\nCDP_element.OuterHTML := htmlstring\t; set html\n\nallattribus := CDP_element.getAttributes() ; gets all the attributes as Object we can use json dump to see whats inside\nvalue := CDP_element.getAttribute(Name) ; getting specific attribute value base on above method\nCDP_element.setAttribute(Name,Value) : change attribute value\n\n; this uses dispatch event with istrusted parameter true\nCDP_element.focus()\nCDP_element.click() ; send click()\nCDP_element.ClickCoord(x,y, delay:= 10) ; send click to a coord\nCDP_element.SendKey(\"1234`n\") ; send 1 2 3 4 enter\n```\n\n# CDP Evaluate(JS)\n`Session.CDP.Evaluate()` executes Javascript, just like we use Chrome's console.\n```AutoHotkey\njs = \n(\nfunction findByTextContent(searchText)\n{\nvar aTags = document.querySelectorAll(\"[Class='mb-4 block-menu-item col-xl-auto col-lg-4 col-sm-6 col-12']\");\nvar found;\nfor (var i = 0; i \u003c aTags.length; i++) {\n  if (aTags[i].textContent == searchText) {\n    found = aTags[i];\n    break;\n  }\n}\nreturn found\n}\n)\nSession.CDP.evaluate(js)\nSession.CDP.evaluate(\"findByTextContent('\" btnName \"').childNodes[0].click()\")\n```\n\n# CDP.Frames\nWe can switch to the frame using CDP methods Just like Basic.\n```AutoHotkey\nMsgBox, % Page.CDP.FramesLength() ; will return child frame length\nPage.CDP.Frame(0) ; switched to Frame 1\nPage.CDP.ParentFrame() ; switched back to Main page / frame\n```\n# CDP Call\nCall is `sendCommand call` for Chrome Devtools protocols, https://chromedevtools.github.io/devtools-protocol/ \nall above methods are Based on CDP.Call() `Session.CDP.call(method,Json_param)`\n```AutoHotkey\nExtList := [\"*.ttf\",\"*.gif\" , \"*.png\" , \"*.jpg\" , \"*.jpeg\" , \"*.webp\"]\nSession.CDP.call(\"Network.enable\")\nSession.CDP.call(\"Network.setBlockedURLs\",{\"urls\": ExtList })\n```\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FXeo786%2FRufaydium-Webdriver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FXeo786%2FRufaydium-Webdriver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FXeo786%2FRufaydium-Webdriver/lists"}