Latest commit

History

273 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

FlaUI.WebDriver

buildCodeQLGitHub LicensePRs Welcome

FlaUI.WebDriver is a W3C WebDriver2 implementation using FlaUI's automation. It currently only supports UIA3.

Important

This WebDriver implementation is EXPERIMENTAL. It is not feature complete and may not implement all features correctly.

Motivation

Capabilities

The following capabilities are supported:

Capability NameDescriptionExample value
platformNameMust be set to windows (case-insensitive).windows
appium:automationNameMust be set to FlaUI (case-insensitive).FlaUI
appium:appThe path to the application, or in case of an UWP app, <package family name>!App. It is also possible to set app to Root. In such case the session will be invoked without any explicit target application. Either this capability, appTopLevelWindow or appTopLevelWindowTitleMatch must be provided on session startup.C:\Windows\System32\notepad.exe, Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
appium:appArgumentsApplication arguments string, for example /?.
appium:appWorkingDirFull path to the folder, which is going to be set as the working dir for the application under test. This is only applicable for classic apps. When this is used the appium:app may contain a relative file path.C:\MyApp\
appium:appTopLevelWindowThe hexadecimal handle of an existing application top level window to attach to, for example 0x12345 (should be of string type). Either this capability, appTopLevelWindowTitleMatch or app must be provided on session startup.0xC0B46
appium:appTopLevelWindowTitleMatchThe title of an existing application top level window to attach to, for example My App Window Title (should be of string type). Either this capability, appTopLevelWindow or app must be provided on session startup.My App Window Title or My App Window Title - .*
appium:newCommandTimeoutThe number of seconds the to wait for clients to send commands before deciding that the client has gone away and the session should shut down. Default one minute (60).120

Getting Started

This driver currently can be downloaded as an executable. Start the web driver service with:

./FlaUI.WebDriver.exe--urls=http://localhost:4723/

After it has started, it can be used via WebDriver clients such as for example:

Using the Appium.WebDriver C# client:

usingOpenQA.Selenium.Appium.Windows;publicclassFlaUIDriverOptions:AppiumOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){returnnewFlaUIDriverOptions(){PlatformName="windows",AutomationName="flaui",App=path};}}vardriver=newWindowsDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the Selenium.WebDriver C# client:

usingOpenQA.Selenium;publicclassFlaUIDriverOptions:DriverOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){varoptions=newFlaUIDriverOptions(){PlatformName="windows"};options.AddAdditionalOption("appium:automationName","flaui");options.AddAdditionalOption("appium:app",path);returnoptions;}publicoverrideICapabilitiesToCapabilities(){returnGenerateDesiredCapabilities(true);}}vardriver=newRemoteWebDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the WebdriverIO JavaScript client:

import{remote}from'webdriverio'constdriver=awaitremote({capabilities: {platformName: 'windows','appium:automationName': 'flaui''appium:app': 'C:\\YourApp.exe'}});

Selectors

On Windows, the recommended selectors, in order of reliability are:

SelectorLocator strategy keywordSupported?
Automation ID"accessibility id"
Name"name"
Class name"class name"
Link text selector"link text"
Partial link text selector"partial link text"
Tag name"tag name"
XPath selector"xpath"
CSS selector"css selector"Only ID, class or name attribute selectors. IDs are interpreted as automation IDs.

Using the Selenium C# client, the selectors are:

driver.FindElement(By.Id("TextBox")).Click();// Matches by automation IDdriver.FindElement(By.Name("TextBox")).Click();driver.FindElement(By.ClassName("TextBox")).Click();driver.FindElement(By.LinkText("Button")).Click();driver.FindElement(By.PartialLinkText("Button")).Click();driver.FindElement(By.TagName("RadioButton")).Click();driver.FindElement(By.XPath("//RadioButton")).Click();

Using the WebdriverIO JavaScript client (see WebdriverIO Selectors guide:

awaitdriver.$('~automationId').click();awaitdriver.$('[name="Name"]').click();awaitdriver.$('.TextBox').click();awaitdriver.$('=Button').click();awaitdriver.$('*=Button').click();awaitdriver.$('<RadioButton />').click();awaitdriver.$('//RadioButton').click();

Windows

The driver supports switching windows. The behavior of windows is as following (identical to behavior of e.g. the Chrome driver):

  • By default, the window is the window that the application was started with.
  • The window does not change if the app/user opens another window, also not if that window happens to be on the foreground.
  • All open window handles from the same app process (same process ID in Windows) can be retrieved.
  • Other processes spawned by the app that open windows are not visible as window handles. Those can be automated by starting a new driver session with e.g. the appium:appTopLevelWindow capability.
  • Closing a window does not automatically switch the window handle. That means that after closing a window, most commands will return an error "no such window" until the window is switched.
  • Switching to a window will set that window in the foreground.

Running scripts

The driver supports PowerShell commands.

Using the Selenium or Appium WebDriver C# client:

varresult=driver.ExecuteScript("powerShell",newDictionary<string,string>{["command"]="1+1"});

Using the WebdriverIO JavaScript client:

constresult=driver.executeScript("powerShell",[{command: `1+1`}]);

Windows extensions

To enable easy switching from appium-windows-driver, there is a rudimentary implementation of windows: click, windows: hover, windows: scroll, windows: keys, windows: getClipboard, windows: setClipboard and windows: clearClipboard.

Supported WebDriver Commands

MethodURI TemplateCommandImplemented
POST/sessionNew Session
DELETE/session/{session id}Delete Session
GET/statusStatus
GET/session/{session id}/timeoutsGet Timeouts
POST/session/{session id}/timeoutsSet Timeouts
POST/session/{session id}/urlNavigate ToN/A
GET/session/{session id}/urlGet Current URLN/A
POST/session/{session id}/backBackN/A
POST/session/{session id}/forwardForwardN/A
POST/session/{session id}/refreshRefreshN/A
GET/session/{session id}/titleGet Title
GET/session/{session id}/windowGet Window Handle
DELETE/session/{session id}/windowClose Window
POST/session/{session id}/windowSwitch To Window
GET/session/{session id}/window/handlesGet Window Handles
POST/session/{session id}/window/newNew Window
POST/session/{session id}/frameSwitch To FrameN/A
POST/session/{session id}/frame/parentSwitch To Parent FrameN/A
GET/session/{session id}/window/rectGet Window Rect
POST/session/{session id}/window/rectSet Window Rect
POST/session/{session id}/window/maximizeMaximize Window
POST/session/{session id}/window/minimizeMinimize Window
POST/session/{session id}/window/fullscreenFullscreen Window
GET/session/{session id}/element/activeGet Active Element
GET/session/{session id}/element/{element id}/shadowGet Element Shadow RootN/A
POST/session/{session id}/elementFind Element
POST/session/{session id}/elementsFind Elements
POST/session/{session id}/element/{element id}/elementFind Element From Element
POST/session/{session id}/element/{element id}/elementsFind Elements From Element
POST/session/{session id}/shadow/{shadow id}/elementFind Element From Shadow RootN/A
POST/session/{session id}/shadow/{shadow id}/elementsFind Elements From Shadow RootN/A
GET/session/{session id}/element/{element id}/selectedIs Element Selected
GET/session/{session id}/element/{element id}/displayedIs Element Displayed1
GET/session/{session id}/element/{element id}/attribute/{name}Get Element Attribute2
GET/session/{session id}/element/{element id}/property/{name}Get Element Property
GET/session/{session id}/element/{element id}/css/{property name}Get Element CSS ValueN/A
GET/session/{session id}/element/{element id}/textGet Element Text
GET/session/{session id}/element/{element id}/nameGet Element Tag Name
GET/session/{session id}/element/{element id}/rectGet Element Rect
GET/session/{session id}/element/{element id}/enabledIs Element Enabled
GET/session/{session id}/element/{element id}/computedroleGet Computed Role
GET/session/{session id}/element/{element id}/computedlabelGet Computed Label
POST/session/{session id}/element/{element id}/clickElement Click
POST/session/{session id}/element/{element id}/clearElement Clear
POST/session/{session id}/element/{element id}/valueElement Send Keys
GET/session/{session id}/sourceGet Page SourceN/A
POST/session/{session id}/execute/syncExecute Script
POST/session/{session id}/execute/asyncExecute Async Script
GET/session/{session id}/cookieGet All CookiesN/A
GET/session/{session id}/cookie/{name}Get Named CookieN/A
POST/session/{session id}/cookieAdd CookieN/A
DELETE/session/{session id}/cookie/{name}Delete CookieN/A
DELETE/session/{session id}/cookieDelete All CookiesN/A
POST/session/{session id}/actionsPerform Actions
DELETE/session/{session id}/actionsRelease Actions
POST/session/{session id}/alert/dismissDismiss Alert
POST/session/{session id}/alert/acceptAccept Alert
GET/session/{session id}/alert/textGet Alert Text
POST/session/{session id}/alert/textSend Alert Text
GET/session/{session id}/screenshotTake Screenshot
GET/session/{session id}/element/{element id}/screenshotTake Element Screenshot
POST/session/{session id}/printPrint Page

WebDriver Interpretation

There is an interpretation to use the WebDriver specification to drive native automation. Appium does not seem to describe that interpretation and leaves it up to the implementer as well. Therefore we describe it here:

WebDriver termInterpretation
browserThe Windows OS on which the FlaUI.WebDriver instance is running
top-level browsing contextsAny window of the app under test (modal windows too)
current top-level browsing contextThe current selected window of the app under test
browsing contextsAny window of the app under test (equal to "top-level browsing contexts")
current browsing contextThe current selected window of the app under test (equal to "current top-level browsing context")
windowAny window of the app under test (modal windows too)
frameNot implemented - frames are only relevant for web browsers
shadow rootNot implemented - shadow DOM is only relevant for web browsers
cookieNot implemented - cookies are only relevant for web browsers
tag nameControl type in Windows
attributeUI automation element property in Windows

Deviations from W3C WebDriver Spec

https://www.w3.org/TR/webdriver2/#element-send-keys says:

Set the text insertion caret using set selection range using current text length for both the start and end parameters.

This is impossible using UIA, as there is no API to set the caret position: text instead gets inserted at the beginning of a text box. This is also WinAppDriver's behavior.

Element Attributes

Attributes are mapped to UI automation element properties. Attributes without a period (.) are mapped to Automation Element Properties. For example to read the UIA_ClassNamePropertyId using Selenium or Appium WebDriver:

varelement=driver.FindElement(By.Id("TextBox"));varvalue=element.GetDomAttribute("ClassName");

Attributes with a period are treated as Control Pattern Properties with the form Pattern.Property. For example to read the UIA_ToggleToggleStatePropertyId using Selenium WebDriver:

varelement=driver.FindElement(By.Id("ToggleButton"));varvalue=element.GetDomAttribute("Toggle.ToggleState");

Next Steps

Possible next steps for this project:

Footnotes

  1. In Selenium WebDriver, the Displayed property converts to javascript. Use Appium WebDriver to use this functionality. It uses the IsOffscreen property that however does not seem to take it into account if the element is blocked by another window.

  2. In Selenium WebDriver, use GetDomAttribute because GetAttribute converts to javascript.

About

No description, website, or topics provided.

Resources

Contributing

Stars

75 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

273 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

FlaUI.WebDriver

buildCodeQLGitHub LicensePRs Welcome

FlaUI.WebDriver is a W3C WebDriver2 implementation using FlaUI's automation. It currently only supports UIA3.

Important

This WebDriver implementation is EXPERIMENTAL. It is not feature complete and may not implement all features correctly.

Motivation

Capabilities

The following capabilities are supported:

Capability NameDescriptionExample value
platformNameMust be set to windows (case-insensitive).windows
appium:automationNameMust be set to FlaUI (case-insensitive).FlaUI
appium:appThe path to the application, or in case of an UWP app, <package family name>!App. It is also possible to set app to Root. In such case the session will be invoked without any explicit target application. Either this capability, appTopLevelWindow or appTopLevelWindowTitleMatch must be provided on session startup.C:\Windows\System32\notepad.exe, Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
appium:appArgumentsApplication arguments string, for example /?.
appium:appWorkingDirFull path to the folder, which is going to be set as the working dir for the application under test. This is only applicable for classic apps. When this is used the appium:app may contain a relative file path.C:\MyApp\
appium:appTopLevelWindowThe hexadecimal handle of an existing application top level window to attach to, for example 0x12345 (should be of string type). Either this capability, appTopLevelWindowTitleMatch or app must be provided on session startup.0xC0B46
appium:appTopLevelWindowTitleMatchThe title of an existing application top level window to attach to, for example My App Window Title (should be of string type). Either this capability, appTopLevelWindow or app must be provided on session startup.My App Window Title or My App Window Title - .*
appium:newCommandTimeoutThe number of seconds the to wait for clients to send commands before deciding that the client has gone away and the session should shut down. Default one minute (60).120

Getting Started

This driver currently can be downloaded as an executable. Start the web driver service with:

./FlaUI.WebDriver.exe--urls=http://localhost:4723/

After it has started, it can be used via WebDriver clients such as for example:

Using the Appium.WebDriver C# client:

usingOpenQA.Selenium.Appium.Windows;publicclassFlaUIDriverOptions:AppiumOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){returnnewFlaUIDriverOptions(){PlatformName="windows",AutomationName="flaui",App=path};}}vardriver=newWindowsDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the Selenium.WebDriver C# client:

usingOpenQA.Selenium;publicclassFlaUIDriverOptions:DriverOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){varoptions=newFlaUIDriverOptions(){PlatformName="windows"};options.AddAdditionalOption("appium:automationName","flaui");options.AddAdditionalOption("appium:app",path);returnoptions;}publicoverrideICapabilitiesToCapabilities(){returnGenerateDesiredCapabilities(true);}}vardriver=newRemoteWebDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the WebdriverIO JavaScript client:

import{remote}from'webdriverio'constdriver=awaitremote({capabilities: {platformName: 'windows','appium:automationName': 'flaui''appium:app': 'C:\\YourApp.exe'}});

Selectors

On Windows, the recommended selectors, in order of reliability are:

SelectorLocator strategy keywordSupported?
Automation ID"accessibility id"
Name"name"
Class name"class name"
Link text selector"link text"
Partial link text selector"partial link text"
Tag name"tag name"
XPath selector"xpath"
CSS selector"css selector"Only ID, class or name attribute selectors. IDs are interpreted as automation IDs.

Using the Selenium C# client, the selectors are:

driver.FindElement(By.Id("TextBox")).Click();// Matches by automation IDdriver.FindElement(By.Name("TextBox")).Click();driver.FindElement(By.ClassName("TextBox")).Click();driver.FindElement(By.LinkText("Button")).Click();driver.FindElement(By.PartialLinkText("Button")).Click();driver.FindElement(By.TagName("RadioButton")).Click();driver.FindElement(By.XPath("//RadioButton")).Click();

Using the WebdriverIO JavaScript client (see WebdriverIO Selectors guide:

awaitdriver.$('~automationId').click();awaitdriver.$('[name="Name"]').click();awaitdriver.$('.TextBox').click();awaitdriver.$('=Button').click();awaitdriver.$('*=Button').click();awaitdriver.$('<RadioButton />').click();awaitdriver.$('//RadioButton').click();

Windows

The driver supports switching windows. The behavior of windows is as following (identical to behavior of e.g. the Chrome driver):

  • By default, the window is the window that the application was started with.
  • The window does not change if the app/user opens another window, also not if that window happens to be on the foreground.
  • All open window handles from the same app process (same process ID in Windows) can be retrieved.
  • Other processes spawned by the app that open windows are not visible as window handles. Those can be automated by starting a new driver session with e.g. the appium:appTopLevelWindow capability.
  • Closing a window does not automatically switch the window handle. That means that after closing a window, most commands will return an error "no such window" until the window is switched.
  • Switching to a window will set that window in the foreground.

Running scripts

The driver supports PowerShell commands.

Using the Selenium or Appium WebDriver C# client:

varresult=driver.ExecuteScript("powerShell",newDictionary<string,string>{["command"]="1+1"});

Using the WebdriverIO JavaScript client:

constresult=driver.executeScript("powerShell",[{command: `1+1`}]);

Windows extensions

To enable easy switching from appium-windows-driver, there is a rudimentary implementation of windows: click, windows: hover, windows: scroll, windows: keys, windows: getClipboard, windows: setClipboard and windows: clearClipboard.

Supported WebDriver Commands

MethodURI TemplateCommandImplemented
POST/sessionNew Session
DELETE/session/{session id}Delete Session
GET/statusStatus
GET/session/{session id}/timeoutsGet Timeouts
POST/session/{session id}/timeoutsSet Timeouts
POST/session/{session id}/urlNavigate ToN/A
GET/session/{session id}/urlGet Current URLN/A
POST/session/{session id}/backBackN/A
POST/session/{session id}/forwardForwardN/A
POST/session/{session id}/refreshRefreshN/A
GET/session/{session id}/titleGet Title
GET/session/{session id}/windowGet Window Handle
DELETE/session/{session id}/windowClose Window
POST/session/{session id}/windowSwitch To Window
GET/session/{session id}/window/handlesGet Window Handles
POST/session/{session id}/window/newNew Window
POST/session/{session id}/frameSwitch To FrameN/A
POST/session/{session id}/frame/parentSwitch To Parent FrameN/A
GET/session/{session id}/window/rectGet Window Rect
POST/session/{session id}/window/rectSet Window Rect
POST/session/{session id}/window/maximizeMaximize Window
POST/session/{session id}/window/minimizeMinimize Window
POST/session/{session id}/window/fullscreenFullscreen Window
GET/session/{session id}/element/activeGet Active Element
GET/session/{session id}/element/{element id}/shadowGet Element Shadow RootN/A
POST/session/{session id}/elementFind Element
POST/session/{session id}/elementsFind Elements
POST/session/{session id}/element/{element id}/elementFind Element From Element
POST/session/{session id}/element/{element id}/elementsFind Elements From Element
POST/session/{session id}/shadow/{shadow id}/elementFind Element From Shadow RootN/A
POST/session/{session id}/shadow/{shadow id}/elementsFind Elements From Shadow RootN/A
GET/session/{session id}/element/{element id}/selectedIs Element Selected
GET/session/{session id}/element/{element id}/displayedIs Element Displayed1
GET/session/{session id}/element/{element id}/attribute/{name}Get Element Attribute2
GET/session/{session id}/element/{element id}/property/{name}Get Element Property
GET/session/{session id}/element/{element id}/css/{property name}Get Element CSS ValueN/A
GET/session/{session id}/element/{element id}/textGet Element Text
GET/session/{session id}/element/{element id}/nameGet Element Tag Name
GET/session/{session id}/element/{element id}/rectGet Element Rect
GET/session/{session id}/element/{element id}/enabledIs Element Enabled
GET/session/{session id}/element/{element id}/computedroleGet Computed Role
GET/session/{session id}/element/{element id}/computedlabelGet Computed Label
POST/session/{session id}/element/{element id}/clickElement Click
POST/session/{session id}/element/{element id}/clearElement Clear
POST/session/{session id}/element/{element id}/valueElement Send Keys
GET/session/{session id}/sourceGet Page SourceN/A
POST/session/{session id}/execute/syncExecute Script
POST/session/{session id}/execute/asyncExecute Async Script
GET/session/{session id}/cookieGet All CookiesN/A
GET/session/{session id}/cookie/{name}Get Named CookieN/A
POST/session/{session id}/cookieAdd CookieN/A
DELETE/session/{session id}/cookie/{name}Delete CookieN/A
DELETE/session/{session id}/cookieDelete All CookiesN/A
POST/session/{session id}/actionsPerform Actions
DELETE/session/{session id}/actionsRelease Actions
POST/session/{session id}/alert/dismissDismiss Alert
POST/session/{session id}/alert/acceptAccept Alert
GET/session/{session id}/alert/textGet Alert Text
POST/session/{session id}/alert/textSend Alert Text
GET/session/{session id}/screenshotTake Screenshot
GET/session/{session id}/element/{element id}/screenshotTake Element Screenshot
POST/session/{session id}/printPrint Page

WebDriver Interpretation

There is an interpretation to use the WebDriver specification to drive native automation. Appium does not seem to describe that interpretation and leaves it up to the implementer as well. Therefore we describe it here:

WebDriver termInterpretation
browserThe Windows OS on which the FlaUI.WebDriver instance is running
top-level browsing contextsAny window of the app under test (modal windows too)
current top-level browsing contextThe current selected window of the app under test
browsing contextsAny window of the app under test (equal to "top-level browsing contexts")
current browsing contextThe current selected window of the app under test (equal to "current top-level browsing context")
windowAny window of the app under test (modal windows too)
frameNot implemented - frames are only relevant for web browsers
shadow rootNot implemented - shadow DOM is only relevant for web browsers
cookieNot implemented - cookies are only relevant for web browsers
tag nameControl type in Windows
attributeUI automation element property in Windows

Deviations from W3C WebDriver Spec

https://www.w3.org/TR/webdriver2/#element-send-keys says:

Set the text insertion caret using set selection range using current text length for both the start and end parameters.

This is impossible using UIA, as there is no API to set the caret position: text instead gets inserted at the beginning of a text box. This is also WinAppDriver's behavior.

Element Attributes

Attributes are mapped to UI automation element properties. Attributes without a period (.) are mapped to Automation Element Properties. For example to read the UIA_ClassNamePropertyId using Selenium or Appium WebDriver:

varelement=driver.FindElement(By.Id("TextBox"));varvalue=element.GetDomAttribute("ClassName");

Attributes with a period are treated as Control Pattern Properties with the form Pattern.Property. For example to read the UIA_ToggleToggleStatePropertyId using Selenium WebDriver:

varelement=driver.FindElement(By.Id("ToggleButton"));varvalue=element.GetDomAttribute("Toggle.ToggleState");

Next Steps

Possible next steps for this project:

Footnotes

  1. In Selenium WebDriver, the Displayed property converts to javascript. Use Appium WebDriver to use this functionality. It uses the IsOffscreen property that however does not seem to take it into account if the element is blocked by another window.

  2. In Selenium WebDriver, use GetDomAttribute because GetAttribute converts to javascript.

About

No description, website, or topics provided.

Resources

Contributing

Stars

75 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

273 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

FlaUI.WebDriver

buildCodeQLGitHub LicensePRs Welcome

FlaUI.WebDriver is a W3C WebDriver2 implementation using FlaUI's automation. It currently only supports UIA3.

Important

This WebDriver implementation is EXPERIMENTAL. It is not feature complete and may not implement all features correctly.

Motivation

Capabilities

The following capabilities are supported:

Capability NameDescriptionExample value
platformNameMust be set to windows (case-insensitive).windows
appium:automationNameMust be set to FlaUI (case-insensitive).FlaUI
appium:appThe path to the application, or in case of an UWP app, <package family name>!App. It is also possible to set app to Root. In such case the session will be invoked without any explicit target application. Either this capability, appTopLevelWindow or appTopLevelWindowTitleMatch must be provided on session startup.C:\Windows\System32\notepad.exe, Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
appium:appArgumentsApplication arguments string, for example /?.
appium:appWorkingDirFull path to the folder, which is going to be set as the working dir for the application under test. This is only applicable for classic apps. When this is used the appium:app may contain a relative file path.C:\MyApp\
appium:appTopLevelWindowThe hexadecimal handle of an existing application top level window to attach to, for example 0x12345 (should be of string type). Either this capability, appTopLevelWindowTitleMatch or app must be provided on session startup.0xC0B46
appium:appTopLevelWindowTitleMatchThe title of an existing application top level window to attach to, for example My App Window Title (should be of string type). Either this capability, appTopLevelWindow or app must be provided on session startup.My App Window Title or My App Window Title - .*
appium:newCommandTimeoutThe number of seconds the to wait for clients to send commands before deciding that the client has gone away and the session should shut down. Default one minute (60).120

Getting Started

This driver currently can be downloaded as an executable. Start the web driver service with:

./FlaUI.WebDriver.exe--urls=http://localhost:4723/

After it has started, it can be used via WebDriver clients such as for example:

Using the Appium.WebDriver C# client:

usingOpenQA.Selenium.Appium.Windows;publicclassFlaUIDriverOptions:AppiumOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){returnnewFlaUIDriverOptions(){PlatformName="windows",AutomationName="flaui",App=path};}}vardriver=newWindowsDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the Selenium.WebDriver C# client:

usingOpenQA.Selenium;publicclassFlaUIDriverOptions:DriverOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){varoptions=newFlaUIDriverOptions(){PlatformName="windows"};options.AddAdditionalOption("appium:automationName","flaui");options.AddAdditionalOption("appium:app",path);returnoptions;}publicoverrideICapabilitiesToCapabilities(){returnGenerateDesiredCapabilities(true);}}vardriver=newRemoteWebDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the WebdriverIO JavaScript client:

import{remote}from'webdriverio'constdriver=awaitremote({capabilities: {platformName: 'windows','appium:automationName': 'flaui''appium:app': 'C:\\YourApp.exe'}});

Selectors

On Windows, the recommended selectors, in order of reliability are:

SelectorLocator strategy keywordSupported?
Automation ID"accessibility id"
Name"name"
Class name"class name"
Link text selector"link text"
Partial link text selector"partial link text"
Tag name"tag name"
XPath selector"xpath"
CSS selector"css selector"Only ID, class or name attribute selectors. IDs are interpreted as automation IDs.

Using the Selenium C# client, the selectors are:

driver.FindElement(By.Id("TextBox")).Click();// Matches by automation IDdriver.FindElement(By.Name("TextBox")).Click();driver.FindElement(By.ClassName("TextBox")).Click();driver.FindElement(By.LinkText("Button")).Click();driver.FindElement(By.PartialLinkText("Button")).Click();driver.FindElement(By.TagName("RadioButton")).Click();driver.FindElement(By.XPath("//RadioButton")).Click();

Using the WebdriverIO JavaScript client (see WebdriverIO Selectors guide:

awaitdriver.$('~automationId').click();awaitdriver.$('[name="Name"]').click();awaitdriver.$('.TextBox').click();awaitdriver.$('=Button').click();awaitdriver.$('*=Button').click();awaitdriver.$('<RadioButton />').click();awaitdriver.$('//RadioButton').click();

Windows

The driver supports switching windows. The behavior of windows is as following (identical to behavior of e.g. the Chrome driver):

  • By default, the window is the window that the application was started with.
  • The window does not change if the app/user opens another window, also not if that window happens to be on the foreground.
  • All open window handles from the same app process (same process ID in Windows) can be retrieved.
  • Other processes spawned by the app that open windows are not visible as window handles. Those can be automated by starting a new driver session with e.g. the appium:appTopLevelWindow capability.
  • Closing a window does not automatically switch the window handle. That means that after closing a window, most commands will return an error "no such window" until the window is switched.
  • Switching to a window will set that window in the foreground.

Running scripts

The driver supports PowerShell commands.

Using the Selenium or Appium WebDriver C# client:

varresult=driver.ExecuteScript("powerShell",newDictionary<string,string>{["command"]="1+1"});

Using the WebdriverIO JavaScript client:

constresult=driver.executeScript("powerShell",[{command: `1+1`}]);

Windows extensions

To enable easy switching from appium-windows-driver, there is a rudimentary implementation of windows: click, windows: hover, windows: scroll, windows: keys, windows: getClipboard, windows: setClipboard and windows: clearClipboard.

Supported WebDriver Commands

MethodURI TemplateCommandImplemented
POST/sessionNew Session
DELETE/session/{session id}Delete Session
GET/statusStatus
GET/session/{session id}/timeoutsGet Timeouts
POST/session/{session id}/timeoutsSet Timeouts
POST/session/{session id}/urlNavigate ToN/A
GET/session/{session id}/urlGet Current URLN/A
POST/session/{session id}/backBackN/A
POST/session/{session id}/forwardForwardN/A
POST/session/{session id}/refreshRefreshN/A
GET/session/{session id}/titleGet Title
GET/session/{session id}/windowGet Window Handle
DELETE/session/{session id}/windowClose Window
POST/session/{session id}/windowSwitch To Window
GET/session/{session id}/window/handlesGet Window Handles
POST/session/{session id}/window/newNew Window
POST/session/{session id}/frameSwitch To FrameN/A
POST/session/{session id}/frame/parentSwitch To Parent FrameN/A
GET/session/{session id}/window/rectGet Window Rect
POST/session/{session id}/window/rectSet Window Rect
POST/session/{session id}/window/maximizeMaximize Window
POST/session/{session id}/window/minimizeMinimize Window
POST/session/{session id}/window/fullscreenFullscreen Window
GET/session/{session id}/element/activeGet Active Element
GET/session/{session id}/element/{element id}/shadowGet Element Shadow RootN/A
POST/session/{session id}/elementFind Element
POST/session/{session id}/elementsFind Elements
POST/session/{session id}/element/{element id}/elementFind Element From Element
POST/session/{session id}/element/{element id}/elementsFind Elements From Element
POST/session/{session id}/shadow/{shadow id}/elementFind Element From Shadow RootN/A
POST/session/{session id}/shadow/{shadow id}/elementsFind Elements From Shadow RootN/A
GET/session/{session id}/element/{element id}/selectedIs Element Selected
GET/session/{session id}/element/{element id}/displayedIs Element Displayed1
GET/session/{session id}/element/{element id}/attribute/{name}Get Element Attribute2
GET/session/{session id}/element/{element id}/property/{name}Get Element Property
GET/session/{session id}/element/{element id}/css/{property name}Get Element CSS ValueN/A
GET/session/{session id}/element/{element id}/textGet Element Text
GET/session/{session id}/element/{element id}/nameGet Element Tag Name
GET/session/{session id}/element/{element id}/rectGet Element Rect
GET/session/{session id}/element/{element id}/enabledIs Element Enabled
GET/session/{session id}/element/{element id}/computedroleGet Computed Role
GET/session/{session id}/element/{element id}/computedlabelGet Computed Label
POST/session/{session id}/element/{element id}/clickElement Click
POST/session/{session id}/element/{element id}/clearElement Clear
POST/session/{session id}/element/{element id}/valueElement Send Keys
GET/session/{session id}/sourceGet Page SourceN/A
POST/session/{session id}/execute/syncExecute Script
POST/session/{session id}/execute/asyncExecute Async Script
GET/session/{session id}/cookieGet All CookiesN/A
GET/session/{session id}/cookie/{name}Get Named CookieN/A
POST/session/{session id}/cookieAdd CookieN/A
DELETE/session/{session id}/cookie/{name}Delete CookieN/A
DELETE/session/{session id}/cookieDelete All CookiesN/A
POST/session/{session id}/actionsPerform Actions
DELETE/session/{session id}/actionsRelease Actions
POST/session/{session id}/alert/dismissDismiss Alert
POST/session/{session id}/alert/acceptAccept Alert
GET/session/{session id}/alert/textGet Alert Text
POST/session/{session id}/alert/textSend Alert Text
GET/session/{session id}/screenshotTake Screenshot
GET/session/{session id}/element/{element id}/screenshotTake Element Screenshot
POST/session/{session id}/printPrint Page

WebDriver Interpretation

There is an interpretation to use the WebDriver specification to drive native automation. Appium does not seem to describe that interpretation and leaves it up to the implementer as well. Therefore we describe it here:

WebDriver termInterpretation
browserThe Windows OS on which the FlaUI.WebDriver instance is running
top-level browsing contextsAny window of the app under test (modal windows too)
current top-level browsing contextThe current selected window of the app under test
browsing contextsAny window of the app under test (equal to "top-level browsing contexts")
current browsing contextThe current selected window of the app under test (equal to "current top-level browsing context")
windowAny window of the app under test (modal windows too)
frameNot implemented - frames are only relevant for web browsers
shadow rootNot implemented - shadow DOM is only relevant for web browsers
cookieNot implemented - cookies are only relevant for web browsers
tag nameControl type in Windows
attributeUI automation element property in Windows

Deviations from W3C WebDriver Spec

https://www.w3.org/TR/webdriver2/#element-send-keys says:

Set the text insertion caret using set selection range using current text length for both the start and end parameters.

This is impossible using UIA, as there is no API to set the caret position: text instead gets inserted at the beginning of a text box. This is also WinAppDriver's behavior.

Element Attributes

Attributes are mapped to UI automation element properties. Attributes without a period (.) are mapped to Automation Element Properties. For example to read the UIA_ClassNamePropertyId using Selenium or Appium WebDriver:

varelement=driver.FindElement(By.Id("TextBox"));varvalue=element.GetDomAttribute("ClassName");

Attributes with a period are treated as Control Pattern Properties with the form Pattern.Property. For example to read the UIA_ToggleToggleStatePropertyId using Selenium WebDriver:

varelement=driver.FindElement(By.Id("ToggleButton"));varvalue=element.GetDomAttribute("Toggle.ToggleState");

Next Steps

Possible next steps for this project:

Footnotes

  1. In Selenium WebDriver, the Displayed property converts to javascript. Use Appium WebDriver to use this functionality. It uses the IsOffscreen property that however does not seem to take it into account if the element is blocked by another window.

  2. In Selenium WebDriver, use GetDomAttribute because GetAttribute converts to javascript.

About

No description, website, or topics provided.

Resources

Contributing

Stars

75 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

273 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

FlaUI.WebDriver

buildCodeQLGitHub LicensePRs Welcome

FlaUI.WebDriver is a W3C WebDriver2 implementation using FlaUI's automation. It currently only supports UIA3.

Important

This WebDriver implementation is EXPERIMENTAL. It is not feature complete and may not implement all features correctly.

Motivation

Capabilities

The following capabilities are supported:

Capability NameDescriptionExample value
platformNameMust be set to windows (case-insensitive).windows
appium:automationNameMust be set to FlaUI (case-insensitive).FlaUI
appium:appThe path to the application, or in case of an UWP app, <package family name>!App. It is also possible to set app to Root. In such case the session will be invoked without any explicit target application. Either this capability, appTopLevelWindow or appTopLevelWindowTitleMatch must be provided on session startup.C:\Windows\System32\notepad.exe, Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
appium:appArgumentsApplication arguments string, for example /?.
appium:appWorkingDirFull path to the folder, which is going to be set as the working dir for the application under test. This is only applicable for classic apps. When this is used the appium:app may contain a relative file path.C:\MyApp\
appium:appTopLevelWindowThe hexadecimal handle of an existing application top level window to attach to, for example 0x12345 (should be of string type). Either this capability, appTopLevelWindowTitleMatch or app must be provided on session startup.0xC0B46
appium:appTopLevelWindowTitleMatchThe title of an existing application top level window to attach to, for example My App Window Title (should be of string type). Either this capability, appTopLevelWindow or app must be provided on session startup.My App Window Title or My App Window Title - .*
appium:newCommandTimeoutThe number of seconds the to wait for clients to send commands before deciding that the client has gone away and the session should shut down. Default one minute (60).120

Getting Started

This driver currently can be downloaded as an executable. Start the web driver service with:

./FlaUI.WebDriver.exe--urls=http://localhost:4723/

After it has started, it can be used via WebDriver clients such as for example:

Using the Appium.WebDriver C# client:

usingOpenQA.Selenium.Appium.Windows;publicclassFlaUIDriverOptions:AppiumOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){returnnewFlaUIDriverOptions(){PlatformName="windows",AutomationName="flaui",App=path};}}vardriver=newWindowsDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the Selenium.WebDriver C# client:

usingOpenQA.Selenium;publicclassFlaUIDriverOptions:DriverOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){varoptions=newFlaUIDriverOptions(){PlatformName="windows"};options.AddAdditionalOption("appium:automationName","flaui");options.AddAdditionalOption("appium:app",path);returnoptions;}publicoverrideICapabilitiesToCapabilities(){returnGenerateDesiredCapabilities(true);}}vardriver=newRemoteWebDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the WebdriverIO JavaScript client:

import{remote}from'webdriverio'constdriver=awaitremote({capabilities: {platformName: 'windows','appium:automationName': 'flaui''appium:app': 'C:\\YourApp.exe'}});

Selectors

On Windows, the recommended selectors, in order of reliability are:

SelectorLocator strategy keywordSupported?
Automation ID"accessibility id"
Name"name"
Class name"class name"
Link text selector"link text"
Partial link text selector"partial link text"
Tag name"tag name"
XPath selector"xpath"
CSS selector"css selector"Only ID, class or name attribute selectors. IDs are interpreted as automation IDs.

Using the Selenium C# client, the selectors are:

driver.FindElement(By.Id("TextBox")).Click();// Matches by automation IDdriver.FindElement(By.Name("TextBox")).Click();driver.FindElement(By.ClassName("TextBox")).Click();driver.FindElement(By.LinkText("Button")).Click();driver.FindElement(By.PartialLinkText("Button")).Click();driver.FindElement(By.TagName("RadioButton")).Click();driver.FindElement(By.XPath("//RadioButton")).Click();

Using the WebdriverIO JavaScript client (see WebdriverIO Selectors guide:

awaitdriver.$('~automationId').click();awaitdriver.$('[name="Name"]').click();awaitdriver.$('.TextBox').click();awaitdriver.$('=Button').click();awaitdriver.$('*=Button').click();awaitdriver.$('<RadioButton />').click();awaitdriver.$('//RadioButton').click();

Windows

The driver supports switching windows. The behavior of windows is as following (identical to behavior of e.g. the Chrome driver):

  • By default, the window is the window that the application was started with.
  • The window does not change if the app/user opens another window, also not if that window happens to be on the foreground.
  • All open window handles from the same app process (same process ID in Windows) can be retrieved.
  • Other processes spawned by the app that open windows are not visible as window handles. Those can be automated by starting a new driver session with e.g. the appium:appTopLevelWindow capability.
  • Closing a window does not automatically switch the window handle. That means that after closing a window, most commands will return an error "no such window" until the window is switched.
  • Switching to a window will set that window in the foreground.

Running scripts

The driver supports PowerShell commands.

Using the Selenium or Appium WebDriver C# client:

varresult=driver.ExecuteScript("powerShell",newDictionary<string,string>{["command"]="1+1"});

Using the WebdriverIO JavaScript client:

constresult=driver.executeScript("powerShell",[{command: `1+1`}]);

Windows extensions

To enable easy switching from appium-windows-driver, there is a rudimentary implementation of windows: click, windows: hover, windows: scroll, windows: keys, windows: getClipboard, windows: setClipboard and windows: clearClipboard.

Supported WebDriver Commands

MethodURI TemplateCommandImplemented
POST/sessionNew Session
DELETE/session/{session id}Delete Session
GET/statusStatus
GET/session/{session id}/timeoutsGet Timeouts
POST/session/{session id}/timeoutsSet Timeouts
POST/session/{session id}/urlNavigate ToN/A
GET/session/{session id}/urlGet Current URLN/A
POST/session/{session id}/backBackN/A
POST/session/{session id}/forwardForwardN/A
POST/session/{session id}/refreshRefreshN/A
GET/session/{session id}/titleGet Title
GET/session/{session id}/windowGet Window Handle
DELETE/session/{session id}/windowClose Window
POST/session/{session id}/windowSwitch To Window
GET/session/{session id}/window/handlesGet Window Handles
POST/session/{session id}/window/newNew Window
POST/session/{session id}/frameSwitch To FrameN/A
POST/session/{session id}/frame/parentSwitch To Parent FrameN/A
GET/session/{session id}/window/rectGet Window Rect
POST/session/{session id}/window/rectSet Window Rect
POST/session/{session id}/window/maximizeMaximize Window
POST/session/{session id}/window/minimizeMinimize Window
POST/session/{session id}/window/fullscreenFullscreen Window
GET/session/{session id}/element/activeGet Active Element
GET/session/{session id}/element/{element id}/shadowGet Element Shadow RootN/A
POST/session/{session id}/elementFind Element
POST/session/{session id}/elementsFind Elements
POST/session/{session id}/element/{element id}/elementFind Element From Element
POST/session/{session id}/element/{element id}/elementsFind Elements From Element
POST/session/{session id}/shadow/{shadow id}/elementFind Element From Shadow RootN/A
POST/session/{session id}/shadow/{shadow id}/elementsFind Elements From Shadow RootN/A
GET/session/{session id}/element/{element id}/selectedIs Element Selected
GET/session/{session id}/element/{element id}/displayedIs Element Displayed1
GET/session/{session id}/element/{element id}/attribute/{name}Get Element Attribute2
GET/session/{session id}/element/{element id}/property/{name}Get Element Property
GET/session/{session id}/element/{element id}/css/{property name}Get Element CSS ValueN/A
GET/session/{session id}/element/{element id}/textGet Element Text
GET/session/{session id}/element/{element id}/nameGet Element Tag Name
GET/session/{session id}/element/{element id}/rectGet Element Rect
GET/session/{session id}/element/{element id}/enabledIs Element Enabled
GET/session/{session id}/element/{element id}/computedroleGet Computed Role
GET/session/{session id}/element/{element id}/computedlabelGet Computed Label
POST/session/{session id}/element/{element id}/clickElement Click
POST/session/{session id}/element/{element id}/clearElement Clear
POST/session/{session id}/element/{element id}/valueElement Send Keys
GET/session/{session id}/sourceGet Page SourceN/A
POST/session/{session id}/execute/syncExecute Script
POST/session/{session id}/execute/asyncExecute Async Script
GET/session/{session id}/cookieGet All CookiesN/A
GET/session/{session id}/cookie/{name}Get Named CookieN/A
POST/session/{session id}/cookieAdd CookieN/A
DELETE/session/{session id}/cookie/{name}Delete CookieN/A
DELETE/session/{session id}/cookieDelete All CookiesN/A
POST/session/{session id}/actionsPerform Actions
DELETE/session/{session id}/actionsRelease Actions
POST/session/{session id}/alert/dismissDismiss Alert
POST/session/{session id}/alert/acceptAccept Alert
GET/session/{session id}/alert/textGet Alert Text
POST/session/{session id}/alert/textSend Alert Text
GET/session/{session id}/screenshotTake Screenshot
GET/session/{session id}/element/{element id}/screenshotTake Element Screenshot
POST/session/{session id}/printPrint Page

WebDriver Interpretation

There is an interpretation to use the WebDriver specification to drive native automation. Appium does not seem to describe that interpretation and leaves it up to the implementer as well. Therefore we describe it here:

WebDriver termInterpretation
browserThe Windows OS on which the FlaUI.WebDriver instance is running
top-level browsing contextsAny window of the app under test (modal windows too)
current top-level browsing contextThe current selected window of the app under test
browsing contextsAny window of the app under test (equal to "top-level browsing contexts")
current browsing contextThe current selected window of the app under test (equal to "current top-level browsing context")
windowAny window of the app under test (modal windows too)
frameNot implemented - frames are only relevant for web browsers
shadow rootNot implemented - shadow DOM is only relevant for web browsers
cookieNot implemented - cookies are only relevant for web browsers
tag nameControl type in Windows
attributeUI automation element property in Windows

Deviations from W3C WebDriver Spec

https://www.w3.org/TR/webdriver2/#element-send-keys says:

Set the text insertion caret using set selection range using current text length for both the start and end parameters.

This is impossible using UIA, as there is no API to set the caret position: text instead gets inserted at the beginning of a text box. This is also WinAppDriver's behavior.

Element Attributes

Attributes are mapped to UI automation element properties. Attributes without a period (.) are mapped to Automation Element Properties. For example to read the UIA_ClassNamePropertyId using Selenium or Appium WebDriver:

varelement=driver.FindElement(By.Id("TextBox"));varvalue=element.GetDomAttribute("ClassName");

Attributes with a period are treated as Control Pattern Properties with the form Pattern.Property. For example to read the UIA_ToggleToggleStatePropertyId using Selenium WebDriver:

varelement=driver.FindElement(By.Id("ToggleButton"));varvalue=element.GetDomAttribute("Toggle.ToggleState");

Next Steps

Possible next steps for this project:

Footnotes

  1. In Selenium WebDriver, the Displayed property converts to javascript. Use Appium WebDriver to use this functionality. It uses the IsOffscreen property that however does not seem to take it into account if the element is blocked by another window.

  2. In Selenium WebDriver, use GetDomAttribute because GetAttribute converts to javascript.

About

No description, website, or topics provided.

Resources

Contributing

Stars

75 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

273 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

FlaUI.WebDriver

buildCodeQLGitHub LicensePRs Welcome

FlaUI.WebDriver is a W3C WebDriver2 implementation using FlaUI's automation. It currently only supports UIA3.

Important

This WebDriver implementation is EXPERIMENTAL. It is not feature complete and may not implement all features correctly.

Motivation

Capabilities

The following capabilities are supported:

Capability NameDescriptionExample value
platformNameMust be set to windows (case-insensitive).windows
appium:automationNameMust be set to FlaUI (case-insensitive).FlaUI
appium:appThe path to the application, or in case of an UWP app, <package family name>!App. It is also possible to set app to Root. In such case the session will be invoked without any explicit target application. Either this capability, appTopLevelWindow or appTopLevelWindowTitleMatch must be provided on session startup.C:\Windows\System32\notepad.exe, Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
appium:appArgumentsApplication arguments string, for example /?.
appium:appWorkingDirFull path to the folder, which is going to be set as the working dir for the application under test. This is only applicable for classic apps. When this is used the appium:app may contain a relative file path.C:\MyApp\
appium:appTopLevelWindowThe hexadecimal handle of an existing application top level window to attach to, for example 0x12345 (should be of string type). Either this capability, appTopLevelWindowTitleMatch or app must be provided on session startup.0xC0B46
appium:appTopLevelWindowTitleMatchThe title of an existing application top level window to attach to, for example My App Window Title (should be of string type). Either this capability, appTopLevelWindow or app must be provided on session startup.My App Window Title or My App Window Title - .*
appium:newCommandTimeoutThe number of seconds the to wait for clients to send commands before deciding that the client has gone away and the session should shut down. Default one minute (60).120

Getting Started

This driver currently can be downloaded as an executable. Start the web driver service with:

./FlaUI.WebDriver.exe--urls=http://localhost:4723/

After it has started, it can be used via WebDriver clients such as for example:

Using the Appium.WebDriver C# client:

usingOpenQA.Selenium.Appium.Windows;publicclassFlaUIDriverOptions:AppiumOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){returnnewFlaUIDriverOptions(){PlatformName="windows",AutomationName="flaui",App=path};}}vardriver=newWindowsDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the Selenium.WebDriver C# client:

usingOpenQA.Selenium;publicclassFlaUIDriverOptions:DriverOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){varoptions=newFlaUIDriverOptions(){PlatformName="windows"};options.AddAdditionalOption("appium:automationName","flaui");options.AddAdditionalOption("appium:app",path);returnoptions;}publicoverrideICapabilitiesToCapabilities(){returnGenerateDesiredCapabilities(true);}}vardriver=newRemoteWebDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the WebdriverIO JavaScript client:

import{remote}from'webdriverio'constdriver=awaitremote({capabilities: {platformName: 'windows','appium:automationName': 'flaui''appium:app': 'C:\\YourApp.exe'}});

Selectors

On Windows, the recommended selectors, in order of reliability are:

SelectorLocator strategy keywordSupported?
Automation ID"accessibility id"
Name"name"
Class name"class name"
Link text selector"link text"
Partial link text selector"partial link text"
Tag name"tag name"
XPath selector"xpath"
CSS selector"css selector"Only ID, class or name attribute selectors. IDs are interpreted as automation IDs.

Using the Selenium C# client, the selectors are:

driver.FindElement(By.Id("TextBox")).Click();// Matches by automation IDdriver.FindElement(By.Name("TextBox")).Click();driver.FindElement(By.ClassName("TextBox")).Click();driver.FindElement(By.LinkText("Button")).Click();driver.FindElement(By.PartialLinkText("Button")).Click();driver.FindElement(By.TagName("RadioButton")).Click();driver.FindElement(By.XPath("//RadioButton")).Click();

Using the WebdriverIO JavaScript client (see WebdriverIO Selectors guide:

awaitdriver.$('~automationId').click();awaitdriver.$('[name="Name"]').click();awaitdriver.$('.TextBox').click();awaitdriver.$('=Button').click();awaitdriver.$('*=Button').click();awaitdriver.$('<RadioButton />').click();awaitdriver.$('//RadioButton').click();

Windows

The driver supports switching windows. The behavior of windows is as following (identical to behavior of e.g. the Chrome driver):

  • By default, the window is the window that the application was started with.
  • The window does not change if the app/user opens another window, also not if that window happens to be on the foreground.
  • All open window handles from the same app process (same process ID in Windows) can be retrieved.
  • Other processes spawned by the app that open windows are not visible as window handles. Those can be automated by starting a new driver session with e.g. the appium:appTopLevelWindow capability.
  • Closing a window does not automatically switch the window handle. That means that after closing a window, most commands will return an error "no such window" until the window is switched.
  • Switching to a window will set that window in the foreground.

Running scripts

The driver supports PowerShell commands.

Using the Selenium or Appium WebDriver C# client:

varresult=driver.ExecuteScript("powerShell",newDictionary<string,string>{["command"]="1+1"});

Using the WebdriverIO JavaScript client:

constresult=driver.executeScript("powerShell",[{command: `1+1`}]);

Windows extensions

To enable easy switching from appium-windows-driver, there is a rudimentary implementation of windows: click, windows: hover, windows: scroll, windows: keys, windows: getClipboard, windows: setClipboard and windows: clearClipboard.

Supported WebDriver Commands

MethodURI TemplateCommandImplemented
POST/sessionNew Session
DELETE/session/{session id}Delete Session
GET/statusStatus
GET/session/{session id}/timeoutsGet Timeouts
POST/session/{session id}/timeoutsSet Timeouts
POST/session/{session id}/urlNavigate ToN/A
GET/session/{session id}/urlGet Current URLN/A
POST/session/{session id}/backBackN/A
POST/session/{session id}/forwardForwardN/A
POST/session/{session id}/refreshRefreshN/A
GET/session/{session id}/titleGet Title
GET/session/{session id}/windowGet Window Handle
DELETE/session/{session id}/windowClose Window
POST/session/{session id}/windowSwitch To Window
GET/session/{session id}/window/handlesGet Window Handles
POST/session/{session id}/window/newNew Window
POST/session/{session id}/frameSwitch To FrameN/A
POST/session/{session id}/frame/parentSwitch To Parent FrameN/A
GET/session/{session id}/window/rectGet Window Rect
POST/session/{session id}/window/rectSet Window Rect
POST/session/{session id}/window/maximizeMaximize Window
POST/session/{session id}/window/minimizeMinimize Window
POST/session/{session id}/window/fullscreenFullscreen Window
GET/session/{session id}/element/activeGet Active Element
GET/session/{session id}/element/{element id}/shadowGet Element Shadow RootN/A
POST/session/{session id}/elementFind Element
POST/session/{session id}/elementsFind Elements
POST/session/{session id}/element/{element id}/elementFind Element From Element
POST/session/{session id}/element/{element id}/elementsFind Elements From Element
POST/session/{session id}/shadow/{shadow id}/elementFind Element From Shadow RootN/A
POST/session/{session id}/shadow/{shadow id}/elementsFind Elements From Shadow RootN/A
GET/session/{session id}/element/{element id}/selectedIs Element Selected
GET/session/{session id}/element/{element id}/displayedIs Element Displayed1
GET/session/{session id}/element/{element id}/attribute/{name}Get Element Attribute2
GET/session/{session id}/element/{element id}/property/{name}Get Element Property
GET/session/{session id}/element/{element id}/css/{property name}Get Element CSS ValueN/A
GET/session/{session id}/element/{element id}/textGet Element Text
GET/session/{session id}/element/{element id}/nameGet Element Tag Name
GET/session/{session id}/element/{element id}/rectGet Element Rect
GET/session/{session id}/element/{element id}/enabledIs Element Enabled
GET/session/{session id}/element/{element id}/computedroleGet Computed Role
GET/session/{session id}/element/{element id}/computedlabelGet Computed Label
POST/session/{session id}/element/{element id}/clickElement Click
POST/session/{session id}/element/{element id}/clearElement Clear
POST/session/{session id}/element/{element id}/valueElement Send Keys
GET/session/{session id}/sourceGet Page SourceN/A
POST/session/{session id}/execute/syncExecute Script
POST/session/{session id}/execute/asyncExecute Async Script
GET/session/{session id}/cookieGet All CookiesN/A
GET/session/{session id}/cookie/{name}Get Named CookieN/A
POST/session/{session id}/cookieAdd CookieN/A
DELETE/session/{session id}/cookie/{name}Delete CookieN/A
DELETE/session/{session id}/cookieDelete All CookiesN/A
POST/session/{session id}/actionsPerform Actions
DELETE/session/{session id}/actionsRelease Actions
POST/session/{session id}/alert/dismissDismiss Alert
POST/session/{session id}/alert/acceptAccept Alert
GET/session/{session id}/alert/textGet Alert Text
POST/session/{session id}/alert/textSend Alert Text
GET/session/{session id}/screenshotTake Screenshot
GET/session/{session id}/element/{element id}/screenshotTake Element Screenshot
POST/session/{session id}/printPrint Page

WebDriver Interpretation

There is an interpretation to use the WebDriver specification to drive native automation. Appium does not seem to describe that interpretation and leaves it up to the implementer as well. Therefore we describe it here:

WebDriver termInterpretation
browserThe Windows OS on which the FlaUI.WebDriver instance is running
top-level browsing contextsAny window of the app under test (modal windows too)
current top-level browsing contextThe current selected window of the app under test
browsing contextsAny window of the app under test (equal to "top-level browsing contexts")
current browsing contextThe current selected window of the app under test (equal to "current top-level browsing context")
windowAny window of the app under test (modal windows too)
frameNot implemented - frames are only relevant for web browsers
shadow rootNot implemented - shadow DOM is only relevant for web browsers
cookieNot implemented - cookies are only relevant for web browsers
tag nameControl type in Windows
attributeUI automation element property in Windows

Deviations from W3C WebDriver Spec

https://www.w3.org/TR/webdriver2/#element-send-keys says:

Set the text insertion caret using set selection range using current text length for both the start and end parameters.

This is impossible using UIA, as there is no API to set the caret position: text instead gets inserted at the beginning of a text box. This is also WinAppDriver's behavior.

Element Attributes

Attributes are mapped to UI automation element properties. Attributes without a period (.) are mapped to Automation Element Properties. For example to read the UIA_ClassNamePropertyId using Selenium or Appium WebDriver:

varelement=driver.FindElement(By.Id("TextBox"));varvalue=element.GetDomAttribute("ClassName");

Attributes with a period are treated as Control Pattern Properties with the form Pattern.Property. For example to read the UIA_ToggleToggleStatePropertyId using Selenium WebDriver:

varelement=driver.FindElement(By.Id("ToggleButton"));varvalue=element.GetDomAttribute("Toggle.ToggleState");

Next Steps

Possible next steps for this project:

Footnotes

  1. In Selenium WebDriver, the Displayed property converts to javascript. Use Appium WebDriver to use this functionality. It uses the IsOffscreen property that however does not seem to take it into account if the element is blocked by another window.

  2. In Selenium WebDriver, use GetDomAttribute because GetAttribute converts to javascript.

About

No description, website, or topics provided.

Resources

Contributing

Stars

75 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

273 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

FlaUI.WebDriver

buildCodeQLGitHub LicensePRs Welcome

FlaUI.WebDriver is a W3C WebDriver2 implementation using FlaUI's automation. It currently only supports UIA3.

Important

This WebDriver implementation is EXPERIMENTAL. It is not feature complete and may not implement all features correctly.

Motivation

Capabilities

The following capabilities are supported:

Capability NameDescriptionExample value
platformNameMust be set to windows (case-insensitive).windows
appium:automationNameMust be set to FlaUI (case-insensitive).FlaUI
appium:appThe path to the application, or in case of an UWP app, <package family name>!App. It is also possible to set app to Root. In such case the session will be invoked without any explicit target application. Either this capability, appTopLevelWindow or appTopLevelWindowTitleMatch must be provided on session startup.C:\Windows\System32\notepad.exe, Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
appium:appArgumentsApplication arguments string, for example /?.
appium:appWorkingDirFull path to the folder, which is going to be set as the working dir for the application under test. This is only applicable for classic apps. When this is used the appium:app may contain a relative file path.C:\MyApp\
appium:appTopLevelWindowThe hexadecimal handle of an existing application top level window to attach to, for example 0x12345 (should be of string type). Either this capability, appTopLevelWindowTitleMatch or app must be provided on session startup.0xC0B46
appium:appTopLevelWindowTitleMatchThe title of an existing application top level window to attach to, for example My App Window Title (should be of string type). Either this capability, appTopLevelWindow or app must be provided on session startup.My App Window Title or My App Window Title - .*
appium:newCommandTimeoutThe number of seconds the to wait for clients to send commands before deciding that the client has gone away and the session should shut down. Default one minute (60).120

Getting Started

This driver currently can be downloaded as an executable. Start the web driver service with:

./FlaUI.WebDriver.exe--urls=http://localhost:4723/

After it has started, it can be used via WebDriver clients such as for example:

Using the Appium.WebDriver C# client:

usingOpenQA.Selenium.Appium.Windows;publicclassFlaUIDriverOptions:AppiumOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){returnnewFlaUIDriverOptions(){PlatformName="windows",AutomationName="flaui",App=path};}}vardriver=newWindowsDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the Selenium.WebDriver C# client:

usingOpenQA.Selenium;publicclassFlaUIDriverOptions:DriverOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){varoptions=newFlaUIDriverOptions(){PlatformName="windows"};options.AddAdditionalOption("appium:automationName","flaui");options.AddAdditionalOption("appium:app",path);returnoptions;}publicoverrideICapabilitiesToCapabilities(){returnGenerateDesiredCapabilities(true);}}vardriver=newRemoteWebDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the WebdriverIO JavaScript client:

import{remote}from'webdriverio'constdriver=awaitremote({capabilities: {platformName: 'windows','appium:automationName': 'flaui''appium:app': 'C:\\YourApp.exe'}});

Selectors

On Windows, the recommended selectors, in order of reliability are:

SelectorLocator strategy keywordSupported?
Automation ID"accessibility id"
Name"name"
Class name"class name"
Link text selector"link text"
Partial link text selector"partial link text"
Tag name"tag name"
XPath selector"xpath"
CSS selector"css selector"Only ID, class or name attribute selectors. IDs are interpreted as automation IDs.

Using the Selenium C# client, the selectors are:

driver.FindElement(By.Id("TextBox")).Click();// Matches by automation IDdriver.FindElement(By.Name("TextBox")).Click();driver.FindElement(By.ClassName("TextBox")).Click();driver.FindElement(By.LinkText("Button")).Click();driver.FindElement(By.PartialLinkText("Button")).Click();driver.FindElement(By.TagName("RadioButton")).Click();driver.FindElement(By.XPath("//RadioButton")).Click();

Using the WebdriverIO JavaScript client (see WebdriverIO Selectors guide:

awaitdriver.$('~automationId').click();awaitdriver.$('[name="Name"]').click();awaitdriver.$('.TextBox').click();awaitdriver.$('=Button').click();awaitdriver.$('*=Button').click();awaitdriver.$('<RadioButton />').click();awaitdriver.$('//RadioButton').click();

Windows

The driver supports switching windows. The behavior of windows is as following (identical to behavior of e.g. the Chrome driver):

  • By default, the window is the window that the application was started with.
  • The window does not change if the app/user opens another window, also not if that window happens to be on the foreground.
  • All open window handles from the same app process (same process ID in Windows) can be retrieved.
  • Other processes spawned by the app that open windows are not visible as window handles. Those can be automated by starting a new driver session with e.g. the appium:appTopLevelWindow capability.
  • Closing a window does not automatically switch the window handle. That means that after closing a window, most commands will return an error "no such window" until the window is switched.
  • Switching to a window will set that window in the foreground.

Running scripts

The driver supports PowerShell commands.

Using the Selenium or Appium WebDriver C# client:

varresult=driver.ExecuteScript("powerShell",newDictionary<string,string>{["command"]="1+1"});

Using the WebdriverIO JavaScript client:

constresult=driver.executeScript("powerShell",[{command: `1+1`}]);

Windows extensions

To enable easy switching from appium-windows-driver, there is a rudimentary implementation of windows: click, windows: hover, windows: scroll, windows: keys, windows: getClipboard, windows: setClipboard and windows: clearClipboard.

Supported WebDriver Commands

MethodURI TemplateCommandImplemented
POST/sessionNew Session
DELETE/session/{session id}Delete Session
GET/statusStatus
GET/session/{session id}/timeoutsGet Timeouts
POST/session/{session id}/timeoutsSet Timeouts
POST/session/{session id}/urlNavigate ToN/A
GET/session/{session id}/urlGet Current URLN/A
POST/session/{session id}/backBackN/A
POST/session/{session id}/forwardForwardN/A
POST/session/{session id}/refreshRefreshN/A
GET/session/{session id}/titleGet Title
GET/session/{session id}/windowGet Window Handle
DELETE/session/{session id}/windowClose Window
POST/session/{session id}/windowSwitch To Window
GET/session/{session id}/window/handlesGet Window Handles
POST/session/{session id}/window/newNew Window
POST/session/{session id}/frameSwitch To FrameN/A
POST/session/{session id}/frame/parentSwitch To Parent FrameN/A
GET/session/{session id}/window/rectGet Window Rect
POST/session/{session id}/window/rectSet Window Rect
POST/session/{session id}/window/maximizeMaximize Window
POST/session/{session id}/window/minimizeMinimize Window
POST/session/{session id}/window/fullscreenFullscreen Window
GET/session/{session id}/element/activeGet Active Element
GET/session/{session id}/element/{element id}/shadowGet Element Shadow RootN/A
POST/session/{session id}/elementFind Element
POST/session/{session id}/elementsFind Elements
POST/session/{session id}/element/{element id}/elementFind Element From Element
POST/session/{session id}/element/{element id}/elementsFind Elements From Element
POST/session/{session id}/shadow/{shadow id}/elementFind Element From Shadow RootN/A
POST/session/{session id}/shadow/{shadow id}/elementsFind Elements From Shadow RootN/A
GET/session/{session id}/element/{element id}/selectedIs Element Selected
GET/session/{session id}/element/{element id}/displayedIs Element Displayed1
GET/session/{session id}/element/{element id}/attribute/{name}Get Element Attribute2
GET/session/{session id}/element/{element id}/property/{name}Get Element Property
GET/session/{session id}/element/{element id}/css/{property name}Get Element CSS ValueN/A
GET/session/{session id}/element/{element id}/textGet Element Text
GET/session/{session id}/element/{element id}/nameGet Element Tag Name
GET/session/{session id}/element/{element id}/rectGet Element Rect
GET/session/{session id}/element/{element id}/enabledIs Element Enabled
GET/session/{session id}/element/{element id}/computedroleGet Computed Role
GET/session/{session id}/element/{element id}/computedlabelGet Computed Label
POST/session/{session id}/element/{element id}/clickElement Click
POST/session/{session id}/element/{element id}/clearElement Clear
POST/session/{session id}/element/{element id}/valueElement Send Keys
GET/session/{session id}/sourceGet Page SourceN/A
POST/session/{session id}/execute/syncExecute Script
POST/session/{session id}/execute/asyncExecute Async Script
GET/session/{session id}/cookieGet All CookiesN/A
GET/session/{session id}/cookie/{name}Get Named CookieN/A
POST/session/{session id}/cookieAdd CookieN/A
DELETE/session/{session id}/cookie/{name}Delete CookieN/A
DELETE/session/{session id}/cookieDelete All CookiesN/A
POST/session/{session id}/actionsPerform Actions
DELETE/session/{session id}/actionsRelease Actions
POST/session/{session id}/alert/dismissDismiss Alert
POST/session/{session id}/alert/acceptAccept Alert
GET/session/{session id}/alert/textGet Alert Text
POST/session/{session id}/alert/textSend Alert Text
GET/session/{session id}/screenshotTake Screenshot
GET/session/{session id}/element/{element id}/screenshotTake Element Screenshot
POST/session/{session id}/printPrint Page

WebDriver Interpretation

There is an interpretation to use the WebDriver specification to drive native automation. Appium does not seem to describe that interpretation and leaves it up to the implementer as well. Therefore we describe it here:

WebDriver termInterpretation
browserThe Windows OS on which the FlaUI.WebDriver instance is running
top-level browsing contextsAny window of the app under test (modal windows too)
current top-level browsing contextThe current selected window of the app under test
browsing contextsAny window of the app under test (equal to "top-level browsing contexts")
current browsing contextThe current selected window of the app under test (equal to "current top-level browsing context")
windowAny window of the app under test (modal windows too)
frameNot implemented - frames are only relevant for web browsers
shadow rootNot implemented - shadow DOM is only relevant for web browsers
cookieNot implemented - cookies are only relevant for web browsers
tag nameControl type in Windows
attributeUI automation element property in Windows

Deviations from W3C WebDriver Spec

https://www.w3.org/TR/webdriver2/#element-send-keys says:

Set the text insertion caret using set selection range using current text length for both the start and end parameters.

This is impossible using UIA, as there is no API to set the caret position: text instead gets inserted at the beginning of a text box. This is also WinAppDriver's behavior.

Element Attributes

Attributes are mapped to UI automation element properties. Attributes without a period (.) are mapped to Automation Element Properties. For example to read the UIA_ClassNamePropertyId using Selenium or Appium WebDriver:

varelement=driver.FindElement(By.Id("TextBox"));varvalue=element.GetDomAttribute("ClassName");

Attributes with a period are treated as Control Pattern Properties with the form Pattern.Property. For example to read the UIA_ToggleToggleStatePropertyId using Selenium WebDriver:

varelement=driver.FindElement(By.Id("ToggleButton"));varvalue=element.GetDomAttribute("Toggle.ToggleState");

Next Steps

Possible next steps for this project:

Footnotes

  1. In Selenium WebDriver, the Displayed property converts to javascript. Use Appium WebDriver to use this functionality. It uses the IsOffscreen property that however does not seem to take it into account if the element is blocked by another window.

  2. In Selenium WebDriver, use GetDomAttribute because GetAttribute converts to javascript.

About

No description, website, or topics provided.

Resources

Contributing

Stars

75 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

273 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

FlaUI.WebDriver

buildCodeQLGitHub LicensePRs Welcome

FlaUI.WebDriver is a W3C WebDriver2 implementation using FlaUI's automation. It currently only supports UIA3.

Important

This WebDriver implementation is EXPERIMENTAL. It is not feature complete and may not implement all features correctly.

Motivation

Capabilities

The following capabilities are supported:

Capability NameDescriptionExample value
platformNameMust be set to windows (case-insensitive).windows
appium:automationNameMust be set to FlaUI (case-insensitive).FlaUI
appium:appThe path to the application, or in case of an UWP app, <package family name>!App. It is also possible to set app to Root. In such case the session will be invoked without any explicit target application. Either this capability, appTopLevelWindow or appTopLevelWindowTitleMatch must be provided on session startup.C:\Windows\System32\notepad.exe, Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
appium:appArgumentsApplication arguments string, for example /?.
appium:appWorkingDirFull path to the folder, which is going to be set as the working dir for the application under test. This is only applicable for classic apps. When this is used the appium:app may contain a relative file path.C:\MyApp\
appium:appTopLevelWindowThe hexadecimal handle of an existing application top level window to attach to, for example 0x12345 (should be of string type). Either this capability, appTopLevelWindowTitleMatch or app must be provided on session startup.0xC0B46
appium:appTopLevelWindowTitleMatchThe title of an existing application top level window to attach to, for example My App Window Title (should be of string type). Either this capability, appTopLevelWindow or app must be provided on session startup.My App Window Title or My App Window Title - .*
appium:newCommandTimeoutThe number of seconds the to wait for clients to send commands before deciding that the client has gone away and the session should shut down. Default one minute (60).120

Getting Started

This driver currently can be downloaded as an executable. Start the web driver service with:

./FlaUI.WebDriver.exe--urls=http://localhost:4723/

After it has started, it can be used via WebDriver clients such as for example:

Using the Appium.WebDriver C# client:

usingOpenQA.Selenium.Appium.Windows;publicclassFlaUIDriverOptions:AppiumOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){returnnewFlaUIDriverOptions(){PlatformName="windows",AutomationName="flaui",App=path};}}vardriver=newWindowsDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the Selenium.WebDriver C# client:

usingOpenQA.Selenium;publicclassFlaUIDriverOptions:DriverOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){varoptions=newFlaUIDriverOptions(){PlatformName="windows"};options.AddAdditionalOption("appium:automationName","flaui");options.AddAdditionalOption("appium:app",path);returnoptions;}publicoverrideICapabilitiesToCapabilities(){returnGenerateDesiredCapabilities(true);}}vardriver=newRemoteWebDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the WebdriverIO JavaScript client:

import{remote}from'webdriverio'constdriver=awaitremote({capabilities: {platformName: 'windows','appium:automationName': 'flaui''appium:app': 'C:\\YourApp.exe'}});

Selectors

On Windows, the recommended selectors, in order of reliability are:

SelectorLocator strategy keywordSupported?
Automation ID"accessibility id"
Name"name"
Class name"class name"
Link text selector"link text"
Partial link text selector"partial link text"
Tag name"tag name"
XPath selector"xpath"
CSS selector"css selector"Only ID, class or name attribute selectors. IDs are interpreted as automation IDs.

Using the Selenium C# client, the selectors are:

driver.FindElement(By.Id("TextBox")).Click();// Matches by automation IDdriver.FindElement(By.Name("TextBox")).Click();driver.FindElement(By.ClassName("TextBox")).Click();driver.FindElement(By.LinkText("Button")).Click();driver.FindElement(By.PartialLinkText("Button")).Click();driver.FindElement(By.TagName("RadioButton")).Click();driver.FindElement(By.XPath("//RadioButton")).Click();

Using the WebdriverIO JavaScript client (see WebdriverIO Selectors guide:

awaitdriver.$('~automationId').click();awaitdriver.$('[name="Name"]').click();awaitdriver.$('.TextBox').click();awaitdriver.$('=Button').click();awaitdriver.$('*=Button').click();awaitdriver.$('<RadioButton />').click();awaitdriver.$('//RadioButton').click();

Windows

The driver supports switching windows. The behavior of windows is as following (identical to behavior of e.g. the Chrome driver):

  • By default, the window is the window that the application was started with.
  • The window does not change if the app/user opens another window, also not if that window happens to be on the foreground.
  • All open window handles from the same app process (same process ID in Windows) can be retrieved.
  • Other processes spawned by the app that open windows are not visible as window handles. Those can be automated by starting a new driver session with e.g. the appium:appTopLevelWindow capability.
  • Closing a window does not automatically switch the window handle. That means that after closing a window, most commands will return an error "no such window" until the window is switched.
  • Switching to a window will set that window in the foreground.

Running scripts

The driver supports PowerShell commands.

Using the Selenium or Appium WebDriver C# client:

varresult=driver.ExecuteScript("powerShell",newDictionary<string,string>{["command"]="1+1"});

Using the WebdriverIO JavaScript client:

constresult=driver.executeScript("powerShell",[{command: `1+1`}]);

Windows extensions

To enable easy switching from appium-windows-driver, there is a rudimentary implementation of windows: click, windows: hover, windows: scroll, windows: keys, windows: getClipboard, windows: setClipboard and windows: clearClipboard.

Supported WebDriver Commands

MethodURI TemplateCommandImplemented
POST/sessionNew Session
DELETE/session/{session id}Delete Session
GET/statusStatus
GET/session/{session id}/timeoutsGet Timeouts
POST/session/{session id}/timeoutsSet Timeouts
POST/session/{session id}/urlNavigate ToN/A
GET/session/{session id}/urlGet Current URLN/A
POST/session/{session id}/backBackN/A
POST/session/{session id}/forwardForwardN/A
POST/session/{session id}/refreshRefreshN/A
GET/session/{session id}/titleGet Title
GET/session/{session id}/windowGet Window Handle
DELETE/session/{session id}/windowClose Window
POST/session/{session id}/windowSwitch To Window
GET/session/{session id}/window/handlesGet Window Handles
POST/session/{session id}/window/newNew Window
POST/session/{session id}/frameSwitch To FrameN/A
POST/session/{session id}/frame/parentSwitch To Parent FrameN/A
GET/session/{session id}/window/rectGet Window Rect
POST/session/{session id}/window/rectSet Window Rect
POST/session/{session id}/window/maximizeMaximize Window
POST/session/{session id}/window/minimizeMinimize Window
POST/session/{session id}/window/fullscreenFullscreen Window
GET/session/{session id}/element/activeGet Active Element
GET/session/{session id}/element/{element id}/shadowGet Element Shadow RootN/A
POST/session/{session id}/elementFind Element
POST/session/{session id}/elementsFind Elements
POST/session/{session id}/element/{element id}/elementFind Element From Element
POST/session/{session id}/element/{element id}/elementsFind Elements From Element
POST/session/{session id}/shadow/{shadow id}/elementFind Element From Shadow RootN/A
POST/session/{session id}/shadow/{shadow id}/elementsFind Elements From Shadow RootN/A
GET/session/{session id}/element/{element id}/selectedIs Element Selected
GET/session/{session id}/element/{element id}/displayedIs Element Displayed1
GET/session/{session id}/element/{element id}/attribute/{name}Get Element Attribute2
GET/session/{session id}/element/{element id}/property/{name}Get Element Property
GET/session/{session id}/element/{element id}/css/{property name}Get Element CSS ValueN/A
GET/session/{session id}/element/{element id}/textGet Element Text
GET/session/{session id}/element/{element id}/nameGet Element Tag Name
GET/session/{session id}/element/{element id}/rectGet Element Rect
GET/session/{session id}/element/{element id}/enabledIs Element Enabled
GET/session/{session id}/element/{element id}/computedroleGet Computed Role
GET/session/{session id}/element/{element id}/computedlabelGet Computed Label
POST/session/{session id}/element/{element id}/clickElement Click
POST/session/{session id}/element/{element id}/clearElement Clear
POST/session/{session id}/element/{element id}/valueElement Send Keys
GET/session/{session id}/sourceGet Page SourceN/A
POST/session/{session id}/execute/syncExecute Script
POST/session/{session id}/execute/asyncExecute Async Script
GET/session/{session id}/cookieGet All CookiesN/A
GET/session/{session id}/cookie/{name}Get Named CookieN/A
POST/session/{session id}/cookieAdd CookieN/A
DELETE/session/{session id}/cookie/{name}Delete CookieN/A
DELETE/session/{session id}/cookieDelete All CookiesN/A
POST/session/{session id}/actionsPerform Actions
DELETE/session/{session id}/actionsRelease Actions
POST/session/{session id}/alert/dismissDismiss Alert
POST/session/{session id}/alert/acceptAccept Alert
GET/session/{session id}/alert/textGet Alert Text
POST/session/{session id}/alert/textSend Alert Text
GET/session/{session id}/screenshotTake Screenshot
GET/session/{session id}/element/{element id}/screenshotTake Element Screenshot
POST/session/{session id}/printPrint Page

WebDriver Interpretation

There is an interpretation to use the WebDriver specification to drive native automation. Appium does not seem to describe that interpretation and leaves it up to the implementer as well. Therefore we describe it here:

WebDriver termInterpretation
browserThe Windows OS on which the FlaUI.WebDriver instance is running
top-level browsing contextsAny window of the app under test (modal windows too)
current top-level browsing contextThe current selected window of the app under test
browsing contextsAny window of the app under test (equal to "top-level browsing contexts")
current browsing contextThe current selected window of the app under test (equal to "current top-level browsing context")
windowAny window of the app under test (modal windows too)
frameNot implemented - frames are only relevant for web browsers
shadow rootNot implemented - shadow DOM is only relevant for web browsers
cookieNot implemented - cookies are only relevant for web browsers
tag nameControl type in Windows
attributeUI automation element property in Windows

Deviations from W3C WebDriver Spec

https://www.w3.org/TR/webdriver2/#element-send-keys says:

Set the text insertion caret using set selection range using current text length for both the start and end parameters.

This is impossible using UIA, as there is no API to set the caret position: text instead gets inserted at the beginning of a text box. This is also WinAppDriver's behavior.

Element Attributes

Attributes are mapped to UI automation element properties. Attributes without a period (.) are mapped to Automation Element Properties. For example to read the UIA_ClassNamePropertyId using Selenium or Appium WebDriver:

varelement=driver.FindElement(By.Id("TextBox"));varvalue=element.GetDomAttribute("ClassName");

Attributes with a period are treated as Control Pattern Properties with the form Pattern.Property. For example to read the UIA_ToggleToggleStatePropertyId using Selenium WebDriver:

varelement=driver.FindElement(By.Id("ToggleButton"));varvalue=element.GetDomAttribute("Toggle.ToggleState");

Next Steps

Possible next steps for this project:

Footnotes

  1. In Selenium WebDriver, the Displayed property converts to javascript. Use Appium WebDriver to use this functionality. It uses the IsOffscreen property that however does not seem to take it into account if the element is blocked by another window.

  2. In Selenium WebDriver, use GetDomAttribute because GetAttribute converts to javascript.

About

No description, website, or topics provided.

Resources

Contributing

Stars

75 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

273 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

FlaUI.WebDriver

buildCodeQLGitHub LicensePRs Welcome

FlaUI.WebDriver is a W3C WebDriver2 implementation using FlaUI's automation. It currently only supports UIA3.

Important

This WebDriver implementation is EXPERIMENTAL. It is not feature complete and may not implement all features correctly.

Motivation

Capabilities

The following capabilities are supported:

Capability NameDescriptionExample value
platformNameMust be set to windows (case-insensitive).windows
appium:automationNameMust be set to FlaUI (case-insensitive).FlaUI
appium:appThe path to the application, or in case of an UWP app, <package family name>!App. It is also possible to set app to Root. In such case the session will be invoked without any explicit target application. Either this capability, appTopLevelWindow or appTopLevelWindowTitleMatch must be provided on session startup.C:\Windows\System32\notepad.exe, Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
appium:appArgumentsApplication arguments string, for example /?.
appium:appWorkingDirFull path to the folder, which is going to be set as the working dir for the application under test. This is only applicable for classic apps. When this is used the appium:app may contain a relative file path.C:\MyApp\
appium:appTopLevelWindowThe hexadecimal handle of an existing application top level window to attach to, for example 0x12345 (should be of string type). Either this capability, appTopLevelWindowTitleMatch or app must be provided on session startup.0xC0B46
appium:appTopLevelWindowTitleMatchThe title of an existing application top level window to attach to, for example My App Window Title (should be of string type). Either this capability, appTopLevelWindow or app must be provided on session startup.My App Window Title or My App Window Title - .*
appium:newCommandTimeoutThe number of seconds the to wait for clients to send commands before deciding that the client has gone away and the session should shut down. Default one minute (60).120

Getting Started

This driver currently can be downloaded as an executable. Start the web driver service with:

./FlaUI.WebDriver.exe--urls=http://localhost:4723/

After it has started, it can be used via WebDriver clients such as for example:

Using the Appium.WebDriver C# client:

usingOpenQA.Selenium.Appium.Windows;publicclassFlaUIDriverOptions:AppiumOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){returnnewFlaUIDriverOptions(){PlatformName="windows",AutomationName="flaui",App=path};}}vardriver=newWindowsDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the Selenium.WebDriver C# client:

usingOpenQA.Selenium;publicclassFlaUIDriverOptions:DriverOptions{publicstaticFlaUIDriverOptionsForApp(stringpath){varoptions=newFlaUIDriverOptions(){PlatformName="windows"};options.AddAdditionalOption("appium:automationName","flaui");options.AddAdditionalOption("appium:app",path);returnoptions;}publicoverrideICapabilitiesToCapabilities(){returnGenerateDesiredCapabilities(true);}}vardriver=newRemoteWebDriver(newUri("http://localhost:4723"),FlaUIDriverOptions.ForApp("C:\\YourApp.exe"))

Using the WebdriverIO JavaScript client:

import{remote}from'webdriverio'constdriver=awaitremote({capabilities: {platformName: 'windows','appium:automationName': 'flaui''appium:app': 'C:\\YourApp.exe'}});

Selectors

On Windows, the recommended selectors, in order of reliability are:

SelectorLocator strategy keywordSupported?
Automation ID"accessibility id"
Name"name"
Class name"class name"
Link text selector"link text"
Partial link text selector"partial link text"
Tag name"tag name"
XPath selector"xpath"
CSS selector"css selector"Only ID, class or name attribute selectors. IDs are interpreted as automation IDs.

Using the Selenium C# client, the selectors are:

driver.FindElement(By.Id("TextBox")).Click();// Matches by automation IDdriver.FindElement(By.Name("TextBox")).Click();driver.FindElement(By.ClassName("TextBox")).Click();driver.FindElement(By.LinkText("Button")).Click();driver.FindElement(By.PartialLinkText("Button")).Click();driver.FindElement(By.TagName("RadioButton")).Click();driver.FindElement(By.XPath("//RadioButton")).Click();

Using the WebdriverIO JavaScript client (see WebdriverIO Selectors guide:

awaitdriver.$('~automationId').click();awaitdriver.$('[name="Name"]').click();awaitdriver.$('.TextBox').click();awaitdriver.$('=Button').click();awaitdriver.$('*=Button').click();awaitdriver.$('<RadioButton />').click();awaitdriver.$('//RadioButton').click();

Windows

The driver supports switching windows. The behavior of windows is as following (identical to behavior of e.g. the Chrome driver):

  • By default, the window is the window that the application was started with.
  • The window does not change if the app/user opens another window, also not if that window happens to be on the foreground.
  • All open window handles from the same app process (same process ID in Windows) can be retrieved.
  • Other processes spawned by the app that open windows are not visible as window handles. Those can be automated by starting a new driver session with e.g. the appium:appTopLevelWindow capability.
  • Closing a window does not automatically switch the window handle. That means that after closing a window, most commands will return an error "no such window" until the window is switched.
  • Switching to a window will set that window in the foreground.

Running scripts

The driver supports PowerShell commands.

Using the Selenium or Appium WebDriver C# client:

varresult=driver.ExecuteScript("powerShell",newDictionary<string,string>{["command"]="1+1"});

Using the WebdriverIO JavaScript client:

constresult=driver.executeScript("powerShell",[{command: `1+1`}]);

Windows extensions

To enable easy switching from appium-windows-driver, there is a rudimentary implementation of windows: click, windows: hover, windows: scroll, windows: keys, windows: getClipboard, windows: setClipboard and windows: clearClipboard.

Supported WebDriver Commands

MethodURI TemplateCommandImplemented
POST/sessionNew Session
DELETE/session/{session id}Delete Session
GET/statusStatus
GET/session/{session id}/timeoutsGet Timeouts
POST/session/{session id}/timeoutsSet Timeouts
POST/session/{session id}/urlNavigate ToN/A
GET/session/{session id}/urlGet Current URLN/A
POST/session/{session id}/backBackN/A
POST/session/{session id}/forwardForwardN/A
POST/session/{session id}/refreshRefreshN/A
GET/session/{session id}/titleGet Title
GET/session/{session id}/windowGet Window Handle
DELETE/session/{session id}/windowClose Window
POST/session/{session id}/windowSwitch To Window
GET/session/{session id}/window/handlesGet Window Handles
POST/session/{session id}/window/newNew Window
POST/session/{session id}/frameSwitch To FrameN/A
POST/session/{session id}/frame/parentSwitch To Parent FrameN/A
GET/session/{session id}/window/rectGet Window Rect
POST/session/{session id}/window/rectSet Window Rect
POST/session/{session id}/window/maximizeMaximize Window
POST/session/{session id}/window/minimizeMinimize Window
POST/session/{session id}/window/fullscreenFullscreen Window
GET/session/{session id}/element/activeGet Active Element
GET/session/{session id}/element/{element id}/shadowGet Element Shadow RootN/A
POST/session/{session id}/elementFind Element
POST/session/{session id}/elementsFind Elements
POST/session/{session id}/element/{element id}/elementFind Element From Element
POST/session/{session id}/element/{element id}/elementsFind Elements From Element
POST/session/{session id}/shadow/{shadow id}/elementFind Element From Shadow RootN/A
POST/session/{session id}/shadow/{shadow id}/elementsFind Elements From Shadow RootN/A
GET/session/{session id}/element/{element id}/selectedIs Element Selected
GET/session/{session id}/element/{element id}/displayedIs Element Displayed1
GET/session/{session id}/element/{element id}/attribute/{name}Get Element Attribute2
GET/session/{session id}/element/{element id}/property/{name}Get Element Property
GET/session/{session id}/element/{element id}/css/{property name}Get Element CSS ValueN/A
GET/session/{session id}/element/{element id}/textGet Element Text
GET/session/{session id}/element/{element id}/nameGet Element Tag Name
GET/session/{session id}/element/{element id}/rectGet Element Rect
GET/session/{session id}/element/{element id}/enabledIs Element Enabled
GET/session/{session id}/element/{element id}/computedroleGet Computed Role
GET/session/{session id}/element/{element id}/computedlabelGet Computed Label
POST/session/{session id}/element/{element id}/clickElement Click
POST/session/{session id}/element/{element id}/clearElement Clear
POST/session/{session id}/element/{element id}/valueElement Send Keys
GET/session/{session id}/sourceGet Page SourceN/A
POST/session/{session id}/execute/syncExecute Script
POST/session/{session id}/execute/asyncExecute Async Script
GET/session/{session id}/cookieGet All CookiesN/A
GET/session/{session id}/cookie/{name}Get Named CookieN/A
POST/session/{session id}/cookieAdd CookieN/A
DELETE/session/{session id}/cookie/{name}Delete CookieN/A
DELETE/session/{session id}/cookieDelete All CookiesN/A
POST/session/{session id}/actionsPerform Actions
DELETE/session/{session id}/actionsRelease Actions
POST/session/{session id}/alert/dismissDismiss Alert
POST/session/{session id}/alert/acceptAccept Alert
GET/session/{session id}/alert/textGet Alert Text
POST/session/{session id}/alert/textSend Alert Text
GET/session/{session id}/screenshotTake Screenshot
GET/session/{session id}/element/{element id}/screenshotTake Element Screenshot
POST/session/{session id}/printPrint Page

WebDriver Interpretation

There is an interpretation to use the WebDriver specification to drive native automation. Appium does not seem to describe that interpretation and leaves it up to the implementer as well. Therefore we describe it here:

WebDriver termInterpretation
browserThe Windows OS on which the FlaUI.WebDriver instance is running
top-level browsing contextsAny window of the app under test (modal windows too)
current top-level browsing contextThe current selected window of the app under test
browsing contextsAny window of the app under test (equal to "top-level browsing contexts")
current browsing contextThe current selected window of the app under test (equal to "current top-level browsing context")
windowAny window of the app under test (modal windows too)
frameNot implemented - frames are only relevant for web browsers
shadow rootNot implemented - shadow DOM is only relevant for web browsers
cookieNot implemented - cookies are only relevant for web browsers
tag nameControl type in Windows
attributeUI automation element property in Windows

Deviations from W3C WebDriver Spec

https://www.w3.org/TR/webdriver2/#element-send-keys says:

Set the text insertion caret using set selection range using current text length for both the start and end parameters.

This is impossible using UIA, as there is no API to set the caret position: text instead gets inserted at the beginning of a text box. This is also WinAppDriver's behavior.

Element Attributes

Attributes are mapped to UI automation element properties. Attributes without a period (.) are mapped to Automation Element Properties. For example to read the UIA_ClassNamePropertyId using Selenium or Appium WebDriver:

varelement=driver.FindElement(By.Id("TextBox"));varvalue=element.GetDomAttribute("ClassName");

Attributes with a period are treated as Control Pattern Properties with the form Pattern.Property. For example to read the UIA_ToggleToggleStatePropertyId using Selenium WebDriver:

varelement=driver.FindElement(By.Id("ToggleButton"));varvalue=element.GetDomAttribute("Toggle.ToggleState");

Next Steps

Possible next steps for this project:

Footnotes

  1. In Selenium WebDriver, the Displayed property converts to javascript. Use Appium WebDriver to use this functionality. It uses the IsOffscreen property that however does not seem to take it into account if the element is blocked by another window.

  2. In Selenium WebDriver, use GetDomAttribute because GetAttribute converts to javascript.

About

No description, website, or topics provided.

Resources

Contributing

Stars

75 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages