├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README_RU.md ├── scripts ├── ci-release.ps1 ├── ci.ps1 ├── prepare-release.ps1 └── setup.ps1 └── src ├── .nuget ├── NuGet.Config └── NuGet.targets ├── Settings.StyleCop ├── TestApps.Tests ├── WindowsFormsTestApplication.Tests │ ├── BaseForMainWindowTest.cs │ ├── BaseTest.cs │ ├── CommandTests │ │ ├── ClearElementTests.cs │ │ ├── ClickElementTests.cs │ │ ├── CloseTests.cs │ │ ├── FindTests.cs │ │ ├── GetActiveElementTests.cs │ │ ├── GetElementAttributeTests.cs │ │ ├── GetElementSizeTests.cs │ │ ├── GetElementTextTests.cs │ │ ├── IsElementDisplayedTests.cs │ │ ├── IsElementEnabledTests.cs │ │ ├── IsElementSelectedTests.cs │ │ ├── MouseClickTests.cs │ │ ├── MouseDoubleClickTests.cs │ │ ├── QuitTests.cs │ │ ├── SendKeysToActiveElementTests.cs │ │ ├── SendKeysToElementTests.cs │ │ └── TakeScreenshotTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── WindowsFormsTestApplication.Tests.csproj │ ├── WindowsFormsTestApplication.exe │ └── packages.config └── WpfTestApplication.Tests │ ├── ActionChainsTests.cs │ ├── BaseForMainWindowTest.cs │ ├── BaseTest.cs │ ├── CommandTests │ ├── ClearElementTests.cs │ ├── ClickElementTests.cs │ ├── CloseTests.cs │ ├── FindTests.cs │ ├── GetActiveElementTests.cs │ ├── GetElementAttributeTests.cs │ ├── GetElementSizeTests.cs │ ├── GetElementTextTests.cs │ ├── IsElementDisplayedTests.cs │ ├── IsElementEnabledTests.cs │ ├── IsElementSelectedTests.cs │ ├── MouseClickTests.cs │ ├── MouseDoubleClickTests.cs │ ├── MouseMoveToTests.cs │ ├── QuitTests.cs │ └── TakeScreenshotTests.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── TestHelper.cs │ ├── TestWebDriver.cs │ ├── WiniumCommandTests │ ├── ComboBoxCommandsTests.cs │ ├── DataGridCommandsTests.cs │ └── MenuCommandsTests.cs │ ├── WpfTestApplication.Tests.csproj │ ├── WpfTestApplication.exe │ └── packages.config ├── Winium.Desktop.Driver ├── App.config ├── Automator │ ├── Automator.cs │ └── Capabilities.cs ├── CommandExecutorDispatchTable.cs ├── CommandExecutors │ ├── ClearElementExecutor.cs │ ├── ClickElementExecutor.cs │ ├── CloseExecutor.cs │ ├── CollapseComboBoxExecutor.cs │ ├── CommandExecutorBase.cs │ ├── ElementEqualsExecutor.cs │ ├── ExecuteScriptExecutor.cs │ ├── ExpandComboBoxExecutor.cs │ ├── FindChildElementExecutor.cs │ ├── FindChildElementsExecutor.cs │ ├── FindComboBoxSelectedItemExecutor.cs │ ├── FindDataGridCellExecutor.cs │ ├── FindElementExecutor.cs │ ├── FindElementsExecutor.cs │ ├── FindMenuItemExecutor.cs │ ├── GetActiveElementExecutor.cs │ ├── GetCurrentWindowHandleExecutor.cs │ ├── GetDataGridColumnCountExecutor.cs │ ├── GetDataGridRowCountExecutor.cs │ ├── GetElementAttributeExecutor.cs │ ├── GetElementSizeExecutor.cs │ ├── GetElementTextExecutor.cs │ ├── GetOrientationExecutor.cs │ ├── GetWindowHandlesExecutor.cs │ ├── ImplicitlyWaitExecutor.cs │ ├── IsComboBoxExpandedExecutor.cs │ ├── IsElementDisplayedExecutor.cs │ ├── IsElementEnabledExecutor.cs │ ├── IsElementSelectedExecutor.cs │ ├── MouseClickExecutor.cs │ ├── MouseDoubleClickExecutor.cs │ ├── MouseMoveToExecutor.cs │ ├── NewSessionExecutor.cs │ ├── NotImplementedExecutor.cs │ ├── QuitExecutor.cs │ ├── ScreenshotExecutor.cs │ ├── ScrollToComboBoxItemExecutor.cs │ ├── ScrollToDataGridCellExecutor.cs │ ├── ScrollToListBoxItemExecutor.cs │ ├── SelectDataGridCellExecutor.cs │ ├── SelectMenuItemExecutor.cs │ ├── SendKeysToActiveElementExecutor.cs │ ├── SendKeysToElementExecutor.cs │ ├── SetOrientationExecutor.cs │ ├── StatusExecutor.cs │ ├── SubmitElementExecutor.cs │ └── SwitchToWindowExecutor.cs ├── CommandHelpers │ ├── BuildInfo.cs │ └── OSInfo.cs ├── CommandLineOptions.cs ├── ElementsRegistry.cs ├── Extensions │ ├── AutomationPropertyHelper.cs │ └── ByHelper.cs ├── HttpRequest.cs ├── Input │ ├── KeyEvent.cs │ ├── KeyboardModifiers.cs │ └── WiniumKeyboard.cs ├── Listener.cs ├── Logger.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── Requester.cs ├── UriDispatchTables.cs ├── Winium.Desktop.Driver.csproj └── packages.config ├── Winium.StoreApps.Common ├── Command.cs ├── CommandInfo.cs ├── CommandResponse.cs ├── DriverCommand.cs ├── Exceptions │ ├── AutomationException.cs │ └── InnerDriverRequestException.cs ├── HttpResponseHelper.cs ├── JsonErrorCodes.cs ├── JsonWireClasses.cs ├── Properties │ └── AssemblyInfo.cs ├── ResponseStatus.cs ├── Winium.StoreApps.Common.csproj └── packages.config ├── Winium.sln └── Winium.sln.DotSettings /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | !build/ 15 | /*/build 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 20 | !packages/*/build/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | *_i.c 27 | *_p.c 28 | *.ilk 29 | *.meta 30 | *.obj 31 | *.pch 32 | *.pdb 33 | *.pgc 34 | *.pgd 35 | *.rsp 36 | *.sbr 37 | *.tlb 38 | *.tli 39 | *.tlh 40 | *.tmp 41 | *.tmp_proj 42 | *.log 43 | *.vspscc 44 | *.vssscc 45 | .builds 46 | *.pidb 47 | *.svclog 48 | *.scc 49 | 50 | # Visual C++ cache files 51 | ipch/ 52 | *.aps 53 | *.ncb 54 | *.opensdf 55 | *.sdf 56 | *.cachefile 57 | 58 | # Visual Studio profiler 59 | *.psess 60 | *.vsp 61 | *.vspx 62 | 63 | # TFS 2012 Local Workspace 64 | $tf/ 65 | 66 | # Guidance Automation Toolkit 67 | *.gpState 68 | 69 | # ReSharper is a .NET coding add-in 70 | _ReSharper*/ 71 | *.[Rr]e[Ss]harper 72 | *.DotSettings.user 73 | 74 | # TeamCity is a build add-in 75 | _TeamCity* 76 | 77 | # DotCover is a Code Coverage Tool 78 | *.dotCover 79 | 80 | # NCrunch 81 | *.ncrunch* 82 | _NCrunch_* 83 | .*crunch*.local.xml 84 | 85 | # Installshield output folder 86 | [Ee]xpress/ 87 | 88 | # DocProject is a documentation generator add-in 89 | DocProject/buildhelp/ 90 | DocProject/Help/*.HxT 91 | DocProject/Help/*.HxC 92 | DocProject/Help/*.hhc 93 | DocProject/Help/*.hhk 94 | DocProject/Help/*.hhp 95 | DocProject/Help/Html2 96 | DocProject/Help/html 97 | 98 | # Click-Once directory 99 | publish/ 100 | 101 | # Publish Web Output 102 | *.Publish.xml 103 | 104 | # NuGet Packages Directory 105 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 106 | packages/ 107 | 108 | # Windows Azure Build Output 109 | csx 110 | *.build.csdef 111 | 112 | # Windows Store app package directory 113 | AppPackages/ 114 | 115 | # Others 116 | sql/ 117 | *.Cache 118 | ClientBin/ 119 | [Ss]tyle[Cc]op.* 120 | ~$* 121 | *~ 122 | *.dbmdl 123 | *.dbproj.schemaview 124 | *.[Pp]ublish.xml 125 | *.pfx 126 | *.publishsettings 127 | 128 | # RIA/Silverlight projects 129 | Generated_Code/ 130 | 131 | # Backup & report files from converting an old project file to a newer 132 | # Visual Studio version. Backup files are not needed, because we have git ;-) 133 | _UpgradeReport_Files/ 134 | Backup*/ 135 | UpgradeLog*.XML 136 | UpgradeLog*.htm 137 | 138 | # SQL Server files 139 | App_Data/*.mdf 140 | App_Data/*.ldf 141 | 142 | # Business Intelligence projects 143 | *.rdl.data 144 | *.bim.layout 145 | *.bim_*.settings 146 | 147 | # Microsoft Fakes 148 | FakesAssemblies/ 149 | 150 | # ========================= 151 | # Windows detritus 152 | # ========================= 153 | 154 | # Windows image file caches 155 | Thumbs.db 156 | ehthumbs.db 157 | 158 | # Folder config file 159 | Desktop.ini 160 | 161 | # Recycle Bin used on file shares 162 | $RECYCLE.BIN/ 163 | 164 | # Mac crap 165 | .DS_Store 166 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | 7 | 8 | ## v1.6.0 9 | 10 | - Add new script command for click to element center (by bounding rectangle). Thanks @kdavydenko 11 | - Add `GetOrientation` and `SetOrientation` command. Thanks @jonstoneman 12 | - Fix listener crashing on empty incoming request (python bindings >2.53.3) 13 | - Fix get attribute response format 14 | 15 | 16 | ## v1.5.0 17 | 18 | - Add `SwitchToWindow` command 19 | - Fix XPath attribute value if this ControlType 20 | 21 | 22 | ## v1.4.0 23 | 24 | - Add `XPath` strategy for locating elements 25 | - Add `GetCurrentWindowHandle` command 26 | - Add `GetWindowHandles` command 27 | - Add `--silent` option to a driver CLI (suppresses output) 28 | - Fix logger timestamp format 29 | 30 | 31 | ## v1.3.0 32 | 33 | - Fix error response format 34 | - Add `args` capability for launching application with arguments 35 | - Set default elements search timeout to 10 seconds (fixed in [Winium.Cruciatus 2.7.0](https://github.com/2gis/Winium.Cruciatus/releases/tag/v2.7.0)) 36 | - Single file Driver distribution 37 | - Add extended driver commands (see [Winium.Elements](https://github.com/2gis/Winium.Elements/releases) for bindings). Extended commands simplify usage of following elements: 38 | - ComboBox (collapse, expand, is expanded, find selected item, scroll to item) 39 | - DataGrid (row count, column count, find cell, scroll to cell, select cell) 40 | - ListBox (scroll to item) 41 | - Menu (find item, select item) 42 | 43 | 44 | ## v1.2.0 45 | 46 | New features: 47 | - Support Action Chains from bindings 48 | - Add new script command for setting value to element using ValuePattern 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | English description | Описание на русском 3 |

4 | 5 | # Winium for Desktop 6 | [![Build Status](https://img.shields.io/jenkins/s/http/opensource-ci.2gis.ru/Winium.Desktop.svg?style=flat-square)](http://opensource-ci.2gis.ru/job/Winium.Desktop/) 7 | [![GitHub release](https://img.shields.io/github/release/2gis/Winium.Desktop.svg?style=flat-square)](https://github.com/2gis/Winium.Desktop/releases/) 8 | [![GitHub license](https://img.shields.io/badge/license-MPL 2.0-blue.svg?style=flat-square)](LICENSE) 9 | 10 |

11 | Winium.Desktop is Selenium Remote WebDriver implementation for automated testing of Windows application based on WinForms and WPF platforms 12 |

13 | 14 | Winium.Desktop is an open source test automation tool for automated testing of Windows application based on WinForms and WPF platforms. 15 | 16 | ## Supported Platforms 17 | - WinForms 18 | - WPF 19 | 20 | For Windows Phone 8.1 test automation tool see [Windows Phone Driver](https://github.com/2gis/Winium.StoreApps). 21 | For Windows Phone 8 Silverlight test automation tool see [Windows Phone Driver](https://github.com/2gis/winphonedriver). 22 | 23 | ## Why Winium? 24 | You have Selenium WebDriver for testing of web apps, Appium for testing of iOS and Android apps. And now you have Selenium-based tools for testing of Windows apps too. What are some of the benefits? As said by Appium: 25 | > - You can write tests with your favorite dev tools using any WebDriver-compatible language such as Java, Objective-C, JavaScript with Node.js (in promise, callback or generator flavors), PHP, Python, Ruby, C#, Clojure, or Perl with the Selenium WebDriver API and language-specific client libraries. 26 | > - You can use any testing framework. 27 | 28 | ## Requirements 29 | * Microsoft .NET Framework 4.5.1 30 | 31 | ## Quick Start 32 | 1. Write your tests using you favorite language. In your tests use `app` [desired capability](https://github.com/2gis/Winium.Desktop/wiki/Capabilities) to set path to tested app's exe file. Here is python example: 33 | ```python 34 | # put it in setUp 35 | self.driver = webdriver.Remote(command_executor='http://localhost:9999', 36 | desired_capabilities={'app': 'C:\\testApp.exe', 37 | 'args': '-port 345'}) 38 | # put it in test method body 39 | win = self.driver.find_element_by_id('WpfTestApplicationMainWindow') 40 | win.find_element_by_id('SetTextButton').click() 41 | assert 'CARAMBA' == self.driver.find_element_by_id('MyTextBox').text 42 | ``` 43 | 44 | 2. Start `Winium.Desktop.Driver.exe` ([download release from github](https://github.com/2gis/Winium.Desktop/releases) or build it yourself) 45 | 46 | 3. Run your tests and watch the magic happening 47 | 48 | ## How it works 49 | **Winium.Desktop.Driver** implements Selenium Remote WebDriver and listens for JsonWireProtocol commands. It is responsible for automation of app under test using [Winium.Cruciatus](https://github.com/2gis/Winium.Cruciatus). 50 | 51 | ## Contributing 52 | 53 | Contributions are welcome! 54 | 55 | 1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. 56 | 2. Fork the repository to start making your changes to the master branch (or branch off of it). 57 | 3. We recommend to write a test which shows that the bug was fixed or that the feature works as expected. 58 | 4. Send a pull request and bug the maintainer until it gets merged and published. :smiley: 59 | 60 | ## Contact 61 | 62 | Have some questions? Found a bug? Create [new issue](https://github.com/2gis/Winium.Desktop/issues/new) or contact us at g.golovin@2gis.ru 63 | 64 | ## License 65 | 66 | Winium is released under the MPL 2.0 license. See [LICENSE](LICENSE) for details. 67 | -------------------------------------------------------------------------------- /README_RU.md: -------------------------------------------------------------------------------- 1 | # Winium для Desktop 2 | [![Build Status](https://img.shields.io/jenkins/s/http/opensource-ci.2gis.ru/Winium.Desktop.svg?style=flat-square)](http://opensource-ci.2gis.ru/job/Winium.Desktop/) 3 | [![GitHub release](https://img.shields.io/github/release/2gis/Winium.Desktop.svg?style=flat-square)](https://github.com/2gis/Winium.Desktop/releases/) 4 | [![GitHub license](https://img.shields.io/badge/license-MPL 2.0-blue.svg?style=flat-square)](LICENSE) 5 | 6 |

7 | Winium.Desktop это реализация Selenium Remote WebDriver для автоматизации тестирования Windows приложений построенных на WinFroms и WPF платформах 8 |

9 | 10 | Winium.Desktop это open-source инструмент для автоматизации тестирования Windows приложений построенных на WinFroms и WPF платформах. 11 | 12 | ## Поддерживаемые платформы 13 | - WinForms 14 | - WPF 15 | 16 | Для автоматизации Windows Phone 8.1 есть [Windows StoreApps Driver](https://github.com/2gis/Winium.StoreApps). 17 | Для автоматизации Windows Phone 8 Silverlight есть [Windows Phone Driver](https://github.com/2gis/winphonedriver). 18 | 19 | ## Почему Winium? 20 | Уже есть Selenium WebDriver для тестирования веб приложений, Appium для тестирования iOS и Android приложений. А теперь появился Selenium-based инструмент для тестирования Windows приложений. Какие он дает преимущества? Цитируя Appium: 21 | > - You can write tests with your favorite dev tools using any WebDriver-compatible language such as Java, Objective-C, JavaScript with Node.js (in promise, callback or generator flavors), PHP, Python, Ruby, C#, Clojure, or Perl with the Selenium WebDriver API and language-specific client libraries. 22 | > - You can use any testing framework. 23 | 24 | А по-русски можно? 25 | - Пишите тесты, используя ваши любимые инструменты, любой WebDriver-совместимый язык программирования, например, Java, Objective-C, JavaScript with Node.js, PHP, Python, Ruby, C#, Clojure... 26 | - Используйте любой тестовый фреймворк. 27 | 28 | ## Требования 29 | * Microsoft .NET Framework 4.5.1 30 | 31 | ## Быстрый старт 32 | 1. Пишите тесты на удобном языке. В тесте используйте `app` [desired capability](https://github.com/2gis/Winium.Desktop/wiki/Capabilities) для задания исполняемого файла приложения. Это пример на python: 33 | ```python 34 | # put it in setUp 35 | self.driver = webdriver.Remote(command_executor='http://localhost:9999', 36 | desired_capabilities={'app': 'C:\\testApp.exe', 37 | 'args': '-port 345'}) 38 | # put it in test method body 39 | win = self.driver.find_element_by_id('WpfTestApplicationMainWindow') 40 | win.find_element_by_id('SetTextButton').click() 41 | assert 'CARAMBA' == self.driver.find_element_by_id('MyTextBox').text 42 | ``` 43 | 44 | 2. Запустите `Winium.Desktop.Driver.exe` ([загрузить последнюю версию с github](https://github.com/2gis/Winium.Desktop/releases) или соберите проект у себя) 45 | 46 | 3. Запустите тесты и балдейте от происходящей магии 47 | 48 | ## Как это работает 49 | **Winium.Desktop.Driver** реализует Selenium Remote WebDriver и слушает команды в JsonWireProtocol. Для автоматизации действий над приложением используется фреймворк [Winium.Cruciatus](https://github.com/2gis/Winium.Cruciatus). 50 | 51 | ## Вклад в развитие 52 | 53 | Мы открыты для сотрудничества! 54 | 55 | 1. Проверьте нет ли уже открытого issue или заведите новый issue для обсуждения новой фичи или бага. 56 | 2. Форкните репозиторий и начните делать свои изменения в ветке мастер или новой ветке 57 | 3. Мы советуем написать тест, который покажет, что баг был починен или что новая фича работает как ожидается. 58 | 4. Создайте pull-request и тыкайте в мэнтейнера до тех пор, пока он не примет и не сольет ваши изменения. :smiley: 59 | 60 | ## Контакты 61 | 62 | Есть вопросы? Нашли ошибку? Создавайте [новое issue](https://github.com/2gis/Winium.Desktop/issues/new) или пишите g.golovin@2gis.ru 63 | 64 | ## Лицензия 65 | 66 | Winium выпущен под MPL 2.0 лицензией. [Подробности](LICENSE). 67 | -------------------------------------------------------------------------------- /scripts/ci-release.ps1: -------------------------------------------------------------------------------- 1 | Set-StrictMode -Version Latest 2 | $ErrorActionPreference = 'Stop' 3 | #------------------------------ 4 | 5 | Import-Module '.\setup.ps1' -Args (,('git', 'versioning', 'changelog', 'msbuild', 'nunit', 'github')) 6 | 7 | $version = $env:release_version 8 | $description = $env:release_description 9 | 10 | # Git checkout master 11 | Invoke-Git ('checkout', 'master') -Verbose 12 | 13 | # Update AssembyInfo 14 | Update-AssemblyInfo $assemblyInfoPath $version -Verbose 15 | 16 | # Update CHANGELOG.md 17 | Update-Changelog $changelogPath $version $description -Verbose 18 | 19 | # Build 20 | Invoke-MSBuild $solution $msbuildProperties -Verbose 21 | 22 | # Test 23 | Start-Process $driverMerged -RedirectStandardError $errorLog -RedirectStandardOutput $outputLog 24 | Invoke-NUnit $testFiles -Verbose 25 | & taskkill ('/im', 'Winium.Desktop.Driver.exe', '/f') 26 | 27 | # Prepare release artifacts 28 | New-Item -ItemType directory -Path $releaseDir | Out-Null 29 | Add-Type -assembly "system.io.compression.filesystem" 30 | $driverMergedPath = Split-Path $driverMerged 31 | [IO.Compression.ZipFile]::CreateFromDirectory($driverMergedPath, "$releaseDir/Winium.Desktop.Driver.zip") 32 | 33 | # Git add changes 34 | Invoke-Git ('add', $assemblyInfoPath) -Verbose 35 | Invoke-Git ('add', $changelogPath) -Verbose 36 | 37 | # Git commit and push 38 | Invoke-GitCommit "Version $version" -Verbose 39 | Invoke-Git ('push', 'origin', 'master') -Verbose 40 | 41 | # Git tag and push 42 | $buildUrl = $env:BUILD_URL 43 | Invoke-GitTag "Version '$version'. Build url '$buildUrl'." "v$version" -Verbose 44 | Invoke-Git ('push', 'origin', 'master', "v$version") -Verbose 45 | 46 | # Create github release 47 | Invoke-CreateGitHubRelease '2gis' $githubProjectName $version $description $releaseDir -Verbose 48 | -------------------------------------------------------------------------------- /scripts/ci.ps1: -------------------------------------------------------------------------------- 1 | Set-StrictMode -Version Latest 2 | $ErrorActionPreference = 'Stop' 3 | #------------------------------ 4 | 5 | Import-Module '.\setup.ps1' -Args (,('msbuild', 'nunit')) 6 | 7 | # Build 8 | Invoke-MSBuild $solution $msbuildProperties -Verbose 9 | 10 | # Test 11 | Start-Process $driverMerged -RedirectStandardError $errorLog -RedirectStandardOutput $outputLog 12 | Invoke-NUnit $testFiles -Verbose 13 | & taskkill ('/im', 'Winium.Desktop.Driver.exe', '/f') 14 | 15 | # Artifacts 16 | New-Item -ItemType directory -Path $artifactsDir | Out-Null 17 | Copy-Item -Path ($errorLog, $outputLog) -Destination $artifactsDir 18 | -------------------------------------------------------------------------------- /scripts/prepare-release.ps1: -------------------------------------------------------------------------------- 1 | Set-StrictMode -Version Latest 2 | $ErrorActionPreference = 'Stop' 3 | #------------------------------ 4 | 5 | Import-Module '.\setup.ps1' -Args (,('msbuild', 'nunit')) 6 | 7 | if (Test-Path $releaseDir) 8 | { 9 | Remove-Item $releaseDir -Force -Recurse 10 | } 11 | 12 | New-Item -ItemType directory -Path $releaseDir | Out-Null 13 | 14 | Write-Output "Update CHANGELOG.md" 15 | Write-Output "Update version in Assemblies" 16 | 17 | Pause 18 | 19 | # Build 20 | Invoke-MSBuild $solution $msbuildProperties -Verbose 21 | 22 | # Test 23 | Start-Process $driverMerged -RedirectStandardError $errorLog -RedirectStandardOutput $outputLog 24 | Invoke-NUnit $testFiles -Verbose 25 | & taskkill ('/im', 'Winium.Desktop.Driver.exe', '/f') 26 | 27 | # Pack driver 28 | Add-Type -assembly "system.io.compression.filesystem" 29 | $driverMergedPath = Split-Path $driverMerged 30 | [IO.Compression.ZipFile]::CreateFromDirectory($driverMergedPath, "$releaseDir/Winium.Desktop.Driver.zip") 31 | 32 | Write-Output "Add and push tag using git tag -a -m 'Version *.*.*' v*.*.*" 33 | Write-Output "Upload and attach $releaseDir\* files to release" 34 | -------------------------------------------------------------------------------- /scripts/setup.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [string[]]$modules 3 | ) 4 | 5 | Set-StrictMode -Version Latest 6 | $ErrorActionPreference = 'Stop' 7 | #------------------------------ 8 | 9 | $configuration = 'Release' 10 | $solution = Join-Path $PSScriptRoot '..\src\Winium.sln' 11 | $testFiles = ,"..\src\TestApps.Tests\WindowsFormsTestApplication.Tests\bin\$configuration\WindowsFormsTestApplication.Tests.dll" 12 | $testFiles += "..\src\TestApps.Tests\WpfTestApplication.Tests\bin\$configuration\WpfTestApplication.Tests.dll" 13 | $releaseDir = Join-Path $PSScriptRoot '..\Release' 14 | $artifactsDir = Join-Path $PSScriptRoot '..\Artifacts' 15 | $driverMerged = "..\src\Winium.Desktop.Driver\bin\$configuration\Merge\Winium.Desktop.Driver.exe" 16 | $errorLog = 'error.log' 17 | $outputLog = 'output.log' 18 | $assemblyInfoPath = Join-Path $PSScriptRoot '..\src\Winium.Desktop.Driver\Properties\AssemblyInfo.cs' 19 | $changelogPath = Join-Path $PSScriptRoot '..\CHANGELOG.md' 20 | $githubProjectName = 'Winium.Desktop' 21 | 22 | $msbuildProperties = @{ 23 | 'Configuration' = $configuration 24 | } 25 | 26 | $modulesUrl = 'https://raw.githubusercontent.com/skyline-gleb/dev-help/v0.2.1/psm' 27 | 28 | if (!(Get-Module -ListAvailable -Name PsGet)) 29 | { 30 | (new-object Net.WebClient).DownloadString("http://psget.net/GetPsGet.ps1") | iex 31 | } 32 | 33 | foreach ($module in $modules) 34 | { 35 | Install-Module -ModuleUrl "$modulesUrl/$module.psm1" -Update 36 | } 37 | -------------------------------------------------------------------------------- /src/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/BaseForMainWindowTest.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class BaseForMainWindowTest : BaseTest 12 | { 13 | #region Public Properties 14 | 15 | public IWebElement MainWindow { get; set; } 16 | 17 | #endregion 18 | 19 | #region Public Methods and Operators 20 | 21 | [SetUp] 22 | public void FindMainWindow() 23 | { 24 | this.MainWindow = this.Driver.FindElement(By.XPath("/*[@AutomationId='Form1']")); 25 | } 26 | 27 | #endregion 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/BaseTest.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.IO; 7 | 8 | using NUnit.Framework; 9 | 10 | using OpenQA.Selenium.Remote; 11 | 12 | #endregion 13 | 14 | public class BaseTest 15 | { 16 | #region Public Properties 17 | 18 | public RemoteWebDriver Driver { get; set; } 19 | 20 | #endregion 21 | 22 | #region Public Methods and Operators 23 | 24 | [SetUp] 25 | public void SetUp() 26 | { 27 | var dc = new DesiredCapabilities(); 28 | dc.SetCapability("app", Path.Combine(Environment.CurrentDirectory, "WindowsFormsTestApplication.exe")); 29 | dc.SetCapability("launchDelay", 2); 30 | this.Driver = new RemoteWebDriver(new Uri("http://localhost:9999"), dc); 31 | } 32 | 33 | [TearDown] 34 | public void TearDown() 35 | { 36 | this.Driver.Close(); 37 | } 38 | 39 | #endregion 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/ClearElementTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class ClearElementTests : BaseForMainWindowTest 12 | { 13 | 14 | #region Public Methods and Operators 15 | 16 | [Test] 17 | public void ClearTextBox() 18 | { 19 | var textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 20 | textBox.Clear(); 21 | 22 | Assert.AreEqual(string.Empty, textBox.Text); 23 | } 24 | 25 | #endregion 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/ClickElementTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | [TestFixture] 12 | public class ClickElementTests : BaseForMainWindowTest 13 | { 14 | #region Public Methods and Operators 15 | 16 | [Test] 17 | public void ClickButtonWhichSetsText() 18 | { 19 | this.MainWindow.FindElement(By.Id("SetTextButton")).Click(); 20 | 21 | Assert.AreEqual("CARAMBA", this.MainWindow.FindElement(By.Id("TextBox1")).Text); 22 | } 23 | 24 | #endregion 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/CloseTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using System.Diagnostics; 6 | 7 | using NUnit.Framework; 8 | 9 | #endregion 10 | 11 | [TestFixture] 12 | public class CloseTests 13 | { 14 | #region Fields 15 | 16 | private Process appProcess; 17 | 18 | private BaseForMainWindowTest baseForMainWindowTest; 19 | 20 | #endregion 21 | 22 | #region Public Methods and Operators 23 | 24 | [Test] 25 | public void CloseApplication() 26 | { 27 | this.baseForMainWindowTest.TearDown(); 28 | 29 | Assert.IsTrue(this.appProcess.HasExited); 30 | } 31 | 32 | [Test, Ignore("Application not have needed elements")] 33 | public void CloseApplicationWithOpenedDialogWindow() 34 | { 35 | // TODO: Extend WindowsFormsTestApplication 36 | } 37 | 38 | [SetUp] 39 | public void SetUp() 40 | { 41 | this.baseForMainWindowTest = new BaseForMainWindowTest(); 42 | this.baseForMainWindowTest.SetUp(); 43 | 44 | this.appProcess = Process.GetProcessesByName("WindowsFormsTestApplication")[0]; 45 | } 46 | 47 | #endregion 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/FindTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | [TestFixture] 12 | public class FindTests : BaseTest 13 | { 14 | #region Public Properties 15 | 16 | public IWebElement MainWindow 17 | { 18 | get 19 | { 20 | var mainWindowStrategy = By.XPath("/*[@AutomationId='Form1']"); 21 | return this.Driver.FindElement(mainWindowStrategy); 22 | } 23 | } 24 | 25 | #endregion 26 | 27 | #region Public Methods and Operators 28 | 29 | [Test] 30 | public void FindChildElementById() 31 | { 32 | var child = this.MainWindow.FindElement(By.Id("TextBox1")); 33 | Assert.NotNull(child); 34 | } 35 | 36 | [Test] 37 | public void FindChildElementByName() 38 | { 39 | var child = this.MainWindow.FindElement(By.Name("TextBox1")); 40 | Assert.NotNull(child); 41 | } 42 | 43 | [Test] 44 | public void FindElementById() 45 | { 46 | var element = this.Driver.FindElement(By.Id("TextBox1")); 47 | Assert.NotNull(element); 48 | } 49 | 50 | [Test] 51 | public void FindElementByName() 52 | { 53 | var element = this.Driver.FindElement(By.Name("TextBox1")); 54 | Assert.NotNull(element); 55 | } 56 | 57 | [Test] 58 | public void FindElements() 59 | { 60 | var comboBox = this.MainWindow.FindElement(By.Id("TextComboBox")); 61 | var elements = comboBox.FindElements(By.Id(string.Empty)); 62 | Assert.AreEqual(6, elements.Count); 63 | } 64 | 65 | [Test] 66 | public void FindNoElements() 67 | { 68 | var elements = this.MainWindow.FindElements(By.Id("UnexistId")); 69 | Assert.AreEqual(0, elements.Count); 70 | } 71 | 72 | #endregion 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/GetActiveElementTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class GetActiveElementTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void GetActiveElement() 17 | { 18 | var textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 19 | textBox.Click(); 20 | 21 | var textBoxToo = this.Driver.SwitchTo().ActiveElement(); 22 | 23 | Assert.IsTrue(textBox.Equals(textBoxToo)); 24 | } 25 | 26 | #endregion 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/GetElementAttributeTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class GetElementAttributeTests : BaseForMainWindowTest 12 | { 13 | #region Fields 14 | 15 | private IWebElement textBox; 16 | 17 | #endregion 18 | 19 | #region Public Methods and Operators 20 | 21 | [SetUp] 22 | public void FindBaseElement() 23 | { 24 | this.textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 25 | } 26 | 27 | [Test] 28 | public void GetNotSupportedAttribute() 29 | { 30 | var value = this.textBox.GetAttribute("InvalidAttributeName"); 31 | 32 | Assert.AreEqual(null, value); 33 | } 34 | 35 | [Test] 36 | public void GetSupportedAttributeByFullPropertyName() 37 | { 38 | var value = this.textBox.GetAttribute("NameProperty"); 39 | 40 | Assert.AreEqual("TextBox1", value); 41 | } 42 | 43 | [Test] 44 | public void GetSupportedAttributeByShortPropertyName() 45 | { 46 | var value = this.textBox.GetAttribute("Name"); 47 | 48 | Assert.AreEqual("TextBox1", value); 49 | } 50 | 51 | #endregion 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/GetElementSizeTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class GetElementSizeTests : BaseTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [TestCase("TextBox1", 200, 20)] 16 | [TestCase("TextListBox", 200, 95)] 17 | public void GetSizeOfElement(string elementId, int width, int height) 18 | { 19 | var mainWindowStrategy = By.XPath("/*[@AutomationId='Form1']"); 20 | var element = this.Driver.FindElement(mainWindowStrategy).FindElement(By.Id(elementId)); 21 | 22 | var size = element.Size; 23 | 24 | Assert.AreEqual(width, size.Width); 25 | Assert.AreEqual(height, size.Height); 26 | } 27 | 28 | #endregion 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/GetElementTextTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class GetElementTextTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void GetTextBoxText() 17 | { 18 | var textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 19 | Assert.AreEqual("TextBox1", textBox.Text); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/IsElementDisplayedTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class IsElementDisplayedTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void IsDisplaydVisibleElement() 17 | { 18 | var element = this.MainWindow.FindElement(By.Id("TextBox1")); 19 | 20 | Assert.IsTrue(element.Displayed); 21 | } 22 | 23 | #endregion 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/IsElementEnabledTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class IsElementEnabledTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void IsDisabledElement() 17 | { 18 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 19 | 20 | var disabledCheckBox = this.MainWindow.FindElement(By.Id("CheckBox1")); 21 | disabledCheckBox.Click(); 22 | 23 | Assert.IsFalse(list.Enabled); 24 | } 25 | 26 | [Test] 27 | public void IsEnabledElement() 28 | { 29 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 30 | 31 | Assert.IsTrue(list.Enabled); 32 | } 33 | 34 | #endregion 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/IsElementSelectedTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class IsElementSelectedTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void IsSelectedCheckBox() 17 | { 18 | var checkbox = this.MainWindow.FindElement(By.Id("CheckBox1")); 19 | 20 | Assert.IsTrue(checkbox.Selected); 21 | } 22 | 23 | [Test] 24 | public void IsSelectedListItem() 25 | { 26 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 27 | var listItem = list.FindElement(By.Name("May")); 28 | 29 | listItem.Click(); 30 | 31 | Assert.IsTrue(listItem.Selected); 32 | } 33 | 34 | [Test] 35 | public void IsSelectedTab() 36 | { 37 | var tab = this.MainWindow.FindElement(By.Name("TabItem1")); 38 | 39 | Assert.IsTrue(tab.Selected); 40 | } 41 | 42 | [Test] 43 | public void IsUnselectedCheckBox() 44 | { 45 | var checkbox = this.MainWindow.FindElement(By.Id("CheckBox1")); 46 | 47 | checkbox.Click(); 48 | 49 | Assert.IsFalse(checkbox.Selected); 50 | } 51 | 52 | [Test] 53 | public void IsUnselectedListItem() 54 | { 55 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 56 | var listItem = list.FindElement(By.Name("May")); 57 | 58 | Assert.IsFalse(listItem.Selected); 59 | } 60 | 61 | [Test] 62 | public void IsUnselectedTab() 63 | { 64 | var tab = this.MainWindow.FindElement(By.Name("TabItem2")); 65 | 66 | Assert.IsFalse(tab.Selected); 67 | } 68 | 69 | #endregion 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/MouseClickTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | using OpenQA.Selenium.Interactions; 9 | 10 | #endregion 11 | 12 | public class MouseClickTests : BaseForMainWindowTest 13 | { 14 | #region Fields 15 | 16 | private Actions action; 17 | 18 | private IWebElement button; 19 | 20 | private IWebElement textBox; 21 | 22 | #endregion 23 | 24 | #region Public Methods and Operators 25 | 26 | [Test] 27 | public void ClickToButton() 28 | { 29 | this.action.MoveToElement(this.button, 1, 1); 30 | this.action.Click(); 31 | this.action.Perform(); 32 | 33 | Assert.AreEqual("CARAMBA", this.textBox.Text); 34 | } 35 | 36 | [SetUp] 37 | public void SetUpForFindElementsAndCreateActionsClass() 38 | { 39 | this.textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 40 | this.button = this.MainWindow.FindElement(By.Id("SetTextButton")); 41 | 42 | this.action = new Actions(this.Driver); 43 | } 44 | 45 | #endregion 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/MouseDoubleClickTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | #endregion 8 | 9 | public class MouseDoubleClickTests : BaseTest 10 | { 11 | #region Public Methods and Operators 12 | 13 | [Test] 14 | [Ignore("Application not have needed elements")] 15 | public void ClickToButton() 16 | { 17 | // TODO: Extend WindowsFormsTestApplication 18 | } 19 | 20 | #endregion 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/QuitTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using System.Diagnostics; 6 | 7 | using NUnit.Framework; 8 | 9 | #endregion 10 | 11 | [TestFixture] 12 | public class QuitTests 13 | { 14 | #region Fields 15 | 16 | private Process appProcess; 17 | 18 | private BaseForMainWindowTest baseForMainWindowTest; 19 | 20 | #endregion 21 | 22 | #region Public Methods and Operators 23 | 24 | [Test] 25 | public void CloseApplication() 26 | { 27 | this.baseForMainWindowTest.Driver.Quit(); 28 | 29 | Assert.IsTrue(this.appProcess.HasExited); 30 | } 31 | 32 | [Test, Ignore("Application not have needed elements")] 33 | public void CloseApplicationWithOpenedDialogWindow() 34 | { 35 | // TODO: Extend WindowsFormsTestApplication 36 | } 37 | 38 | [SetUp] 39 | public void SetUp() 40 | { 41 | this.baseForMainWindowTest = new BaseForMainWindowTest(); 42 | this.baseForMainWindowTest.SetUp(); 43 | 44 | this.appProcess = Process.GetProcessesByName("WindowsFormsTestApplication")[0]; 45 | } 46 | 47 | #endregion 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/SendKeysToActiveElementTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class SendKeysToActiveElementTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void SendKeysToActiveElement() 17 | { 18 | var textbox = this.MainWindow.FindElement(By.Id("TextBox1")); 19 | textbox.Click(); 20 | 21 | this.Driver.Keyboard.SendKeys("test"); 22 | 23 | Assert.AreEqual("TextBox1test", textbox.Text); 24 | } 25 | 26 | #endregion 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/SendKeysToElementTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class SendKeysToElementTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void SendEmptyKeysToElement() 17 | { 18 | var textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 19 | textBox.SendKeys(string.Empty); 20 | 21 | Assert.AreEqual(string.Empty, textBox.Text); 22 | } 23 | 24 | [Test] 25 | public void SendKeysToElement() 26 | { 27 | const string NewText = "new test text"; 28 | 29 | var textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 30 | textBox.SendKeys(NewText); 31 | 32 | Assert.AreEqual(NewText, textBox.Text); 33 | } 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/CommandTests/TakeScreenshotTests.cs: -------------------------------------------------------------------------------- 1 | namespace WindowsFormsTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | #endregion 8 | 9 | public class TakeScreenshotTests : BaseTest 10 | { 11 | #region Public Methods and Operators 12 | 13 | [Test] 14 | public void IsSelectedListItem() 15 | { 16 | var screenshot = this.Driver.GetScreenshot().ToString(); 17 | Assert.That(screenshot.Length, Is.GreaterThan(0)); 18 | } 19 | 20 | #endregion 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region using 2 | 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | 6 | #endregion 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | [assembly: AssemblyTitle("WindowsFormsTestApplication.Tests")] 12 | [assembly: AssemblyDescription("")] 13 | [assembly: AssemblyConfiguration("")] 14 | [assembly: AssemblyCompany("")] 15 | [assembly: AssemblyProduct("WindowsFormsTestApplication.Tests")] 16 | [assembly: AssemblyCopyright("Copyright © 2015")] 17 | [assembly: AssemblyTrademark("")] 18 | [assembly: AssemblyCulture("")] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | [assembly: ComVisible(false)] 24 | 25 | // The following GUID is for the ID of the typelib if this project is exposed to COM 26 | [assembly: Guid("a12835c0-d656-4420-b3e8-271218eea250")] 27 | 28 | // Version information for an assembly consists of the following four values: 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.0.0.0")] 37 | [assembly: AssemblyFileVersion("1.0.0.0")] 38 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/WindowsFormsTestApplication.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DC69009A-39E7-4F02-B721-3CC99B4EA637} 8 | Library 9 | Properties 10 | WindowsFormsTestApplication.Tests 11 | WindowsFormsTestApplication.Tests 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll 37 | True 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ..\..\packages\Selenium.WebDriver.2.53.1\lib\net40\WebDriver.dll 46 | True 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Always 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 85 | 86 | 87 | 88 | 95 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/WindowsFormsTestApplication.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2gis/Winium.Desktop/bc4999ecc5c452839058a71054c685db8854f5c9/src/TestApps.Tests/WindowsFormsTestApplication.Tests/WindowsFormsTestApplication.exe -------------------------------------------------------------------------------- /src/TestApps.Tests/WindowsFormsTestApplication.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/ActionChainsTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests 2 | { 3 | #region using 4 | 5 | using System.Linq; 6 | 7 | using NUnit.Framework; 8 | 9 | using OpenQA.Selenium; 10 | using OpenQA.Selenium.Interactions; 11 | 12 | #endregion 13 | 14 | [TestFixture] 15 | public class ActionChainsTests : BaseForMainWindowTest 16 | { 17 | #region Public Methods and Operators 18 | 19 | [Test] 20 | public void KeyUpAndKeyDown() 21 | { 22 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 23 | var items = list.FindElements(By.ClassName("ListBoxItem")); 24 | var first = items.First(); 25 | var random = items.ElementAt(3); 26 | var actions = new Actions(this.Driver); 27 | 28 | actions.Click(first).KeyDown(Keys.Shift).Click(random).KeyUp(Keys.Shift).Perform(); 29 | 30 | var selectedItemsCount = list.FindElements(By.ClassName("ListBoxItem")).Count(item => item.Selected); 31 | 32 | Assert.AreEqual(4, selectedItemsCount); 33 | } 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/BaseForMainWindowTest.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | using OpenQA.Selenium.Remote; 9 | 10 | #endregion 11 | 12 | public class BaseForMainWindowTest : BaseTest 13 | { 14 | #region Public Properties 15 | 16 | public IWebElement MainWindow { get; set; } 17 | 18 | #endregion 19 | 20 | #region Public Methods and Operators 21 | 22 | [SetUp] 23 | public void FindMainWindow() 24 | { 25 | this.MainWindow = this.Driver.FindElement(By.XPath("/*[@AutomationId='WpfTestApplicationMainWindow']")); 26 | } 27 | 28 | #endregion 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/BaseTest.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.IO; 7 | 8 | using NUnit.Framework; 9 | 10 | using OpenQA.Selenium; 11 | using OpenQA.Selenium.Remote; 12 | 13 | #endregion 14 | 15 | public class BaseTest 16 | where TDriver : class, IWebDriver 17 | { 18 | #region Public Properties 19 | 20 | public TDriver Driver { get; set; } 21 | 22 | #endregion 23 | 24 | #region Public Methods and Operators 25 | 26 | [SetUp] 27 | public void SetUp() 28 | { 29 | var dc = new DesiredCapabilities(); 30 | dc.SetCapability("app", Path.Combine(Environment.CurrentDirectory, "WpfTestApplication.exe")); 31 | dc.SetCapability("launchDelay", 2); 32 | this.Driver = Activator.CreateInstance(typeof(TDriver), new Uri("http://localhost:9999"), dc) as TDriver; 33 | } 34 | 35 | [TearDown] 36 | public void TearDown() 37 | { 38 | this.Driver.Close(); 39 | } 40 | 41 | #endregion 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/ClearElementTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class ClearElementTests : BaseForMainWindowTest 12 | { 13 | 14 | #region Public Methods and Operators 15 | 16 | [Test] 17 | public void ClearTextBox() 18 | { 19 | var textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 20 | textBox.Clear(); 21 | 22 | Assert.AreEqual(string.Empty, textBox.Text); 23 | } 24 | 25 | #endregion 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/ClickElementTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | [TestFixture] 12 | public class ClickElementTests : BaseForMainWindowTest 13 | { 14 | #region Public Methods and Operators 15 | 16 | [Test] 17 | public void ClickButtonWhichSetsText() 18 | { 19 | this.MainWindow.FindElement(By.Id("SetTextButton")).Click(); 20 | 21 | Assert.AreEqual("CARAMBA", this.MainWindow.FindElement(By.Id("TextBox1")).Text); 22 | } 23 | 24 | [Test] 25 | public void ClickByTwoElementsWithPressedControl() 26 | { 27 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 28 | 29 | var listItem1 = list.FindElement(By.Name("March")); 30 | var listItem2 = list.FindElement(By.Name("January")); 31 | var listItem3 = list.FindElement(By.Name("February")); 32 | 33 | this.Driver.ExecuteScript("input: ctrl_click", listItem1); 34 | this.Driver.ExecuteScript("input: ctrl_click", listItem2); 35 | 36 | Assert.IsTrue(listItem1.Selected); 37 | Assert.IsTrue(listItem2.Selected); 38 | Assert.IsFalse(listItem3.Selected); 39 | } 40 | 41 | [Test] 42 | public void ClickByElementBoundingRecatngleCenter() 43 | { 44 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 45 | 46 | var listItem1 = list.FindElement(By.Name("March")); 47 | 48 | this.Driver.ExecuteScript("input: brc_click", listItem1); 49 | 50 | Assert.IsTrue(listItem1.Selected); 51 | } 52 | 53 | #endregion 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/CloseTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using System.Diagnostics; 6 | 7 | using NUnit.Framework; 8 | 9 | using OpenQA.Selenium; 10 | 11 | #endregion 12 | 13 | [TestFixture] 14 | public class CloseTests 15 | { 16 | #region Fields 17 | 18 | private Process appProcess; 19 | 20 | private BaseForMainWindowTest baseForMainWindowTest; 21 | 22 | #endregion 23 | 24 | #region Public Methods and Operators 25 | 26 | [Test] 27 | public void CloseApplication() 28 | { 29 | this.baseForMainWindowTest.TearDown(); 30 | 31 | Assert.IsTrue(this.appProcess.HasExited); 32 | } 33 | 34 | [Test] 35 | public void CloseApplicationWithOpenedDialogWindow() 36 | { 37 | this.baseForMainWindowTest.FindMainWindow(); 38 | var tabItem3 = this.baseForMainWindowTest.MainWindow.FindElement(By.Id("TabItem3")); 39 | tabItem3.Click(); 40 | tabItem3.FindElement(By.Id("OpenFileDialogButton")).Click(); 41 | 42 | this.baseForMainWindowTest.TearDown(); 43 | 44 | Assert.IsTrue(this.appProcess.HasExited); 45 | } 46 | 47 | [SetUp] 48 | public void SetUp() 49 | { 50 | this.baseForMainWindowTest = new BaseForMainWindowTest(); 51 | this.baseForMainWindowTest.SetUp(); 52 | 53 | this.appProcess = Process.GetProcessesByName("WpfTestApplication")[0]; 54 | } 55 | 56 | #endregion 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/FindTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | using OpenQA.Selenium.Remote; 9 | 10 | #endregion 11 | 12 | [TestFixture] 13 | public class FindTests : BaseTest 14 | { 15 | #region Public Properties 16 | 17 | public IWebElement MainWindow 18 | { 19 | get 20 | { 21 | var mainWindowStrategy = By.XPath("/*[@AutomationId='WpfTestApplicationMainWindow']"); 22 | return this.Driver.FindElement(mainWindowStrategy); 23 | } 24 | } 25 | 26 | #endregion 27 | 28 | #region Public Methods and Operators 29 | 30 | [Test] 31 | public void FindChildElementByClassName() 32 | { 33 | var child = this.MainWindow.FindElement(By.ClassName("TextBox")); 34 | Assert.NotNull(child); 35 | } 36 | 37 | [Test] 38 | public void FindChildElementById() 39 | { 40 | var child = this.MainWindow.FindElement(By.Id("TextBox1")); 41 | Assert.NotNull(child); 42 | } 43 | 44 | [Test] 45 | public void FindChildElementByName() 46 | { 47 | var child = this.MainWindow.FindElement(By.Name("IsEnabledTextListBox")); 48 | Assert.NotNull(child); 49 | } 50 | 51 | [Test] 52 | public void FindElementByClassName() 53 | { 54 | var element = this.Driver.FindElement(By.ClassName("Window")); 55 | Assert.NotNull(element); 56 | } 57 | 58 | [Test] 59 | public void FindElementById() 60 | { 61 | var element = this.MainWindow; 62 | Assert.NotNull(element); 63 | } 64 | 65 | [Test] 66 | public void FindElementByName() 67 | { 68 | var element = this.Driver.FindElement(By.Name("MainWindow")); 69 | Assert.NotNull(element); 70 | } 71 | 72 | [Test] 73 | public void FindElements() 74 | { 75 | var comboBox = this.MainWindow.FindElement(By.Id("TextComboBox")); 76 | comboBox.Click(); 77 | 78 | var elements = comboBox.FindElements(By.ClassName("ListBoxItem")); 79 | Assert.AreEqual(6, elements.Count); 80 | } 81 | 82 | [Test] 83 | public void FindNoElements() 84 | { 85 | var elements = this.MainWindow.FindElements(By.Id("UnexistId")); 86 | Assert.AreEqual(0, elements.Count); 87 | } 88 | 89 | #endregion 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/GetActiveElementTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class GetActiveElementTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void GetActiveElement() 17 | { 18 | var textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 19 | textBox.Click(); 20 | 21 | var textBoxToo = this.Driver.SwitchTo().ActiveElement(); 22 | 23 | Assert.IsTrue(textBox.Equals(textBoxToo)); 24 | } 25 | 26 | #endregion 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/GetElementAttributeTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class GetElementAttributeTests : BaseForMainWindowTest 12 | { 13 | #region Fields 14 | 15 | private IWebElement textBox; 16 | 17 | #endregion 18 | 19 | #region Public Methods and Operators 20 | 21 | [SetUp] 22 | public void FindBaseElement() 23 | { 24 | this.textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 25 | } 26 | 27 | [Test] 28 | public void GetNotSupportedAttribute() 29 | { 30 | var value = this.textBox.GetAttribute("InvalidAttributeName"); 31 | 32 | Assert.AreEqual(null, value); 33 | } 34 | 35 | [Test] 36 | public void GetSupportedAttributeByFullPropertyName() 37 | { 38 | var value = this.textBox.GetAttribute("ClassNameProperty"); 39 | 40 | Assert.AreEqual("TextBox", value); 41 | } 42 | 43 | [Test] 44 | public void GetSupportedAttributeByShortPropertyName() 45 | { 46 | var value = this.textBox.GetAttribute("ClassName"); 47 | 48 | Assert.AreEqual("TextBox", value); 49 | } 50 | 51 | #endregion 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/GetElementSizeTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | using OpenQA.Selenium.Remote; 9 | 10 | #endregion 11 | 12 | public class GetElementSizeTests : BaseTest 13 | { 14 | #region Public Methods and Operators 15 | 16 | [TestCase("TextBox1", 200, 23)] 17 | [TestCase("TextListBox", 200, 100)] 18 | public void GetSizeOfElement(string elementId, int width, int height) 19 | { 20 | var mainWindowStrategy = By.XPath("/*[@AutomationId='WpfTestApplicationMainWindow']"); 21 | var element = this.Driver.FindElement(mainWindowStrategy).FindElement(By.Id(elementId)); 22 | 23 | var size = element.Size; 24 | 25 | Assert.AreEqual(width, size.Width); 26 | Assert.AreEqual(height, size.Height); 27 | } 28 | 29 | #endregion 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/GetElementTextTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class GetElementTextTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void GetTextBoxText() 17 | { 18 | var textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 19 | Assert.AreEqual("TextBox1", textBox.Text); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/IsElementDisplayedTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class IsElementDisplayedTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void IsDisplaydVisibleElement() 17 | { 18 | var element = this.MainWindow.FindElement(By.Id("TextBox1")); 19 | 20 | Assert.IsTrue(element.Displayed); 21 | } 22 | 23 | #endregion 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/IsElementEnabledTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class IsElementEnabledTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void IsDisabledElement() 17 | { 18 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 19 | 20 | var disabledCheckBox = this.MainWindow.FindElement(By.Id("CheckBox1")); 21 | disabledCheckBox.Click(); 22 | 23 | Assert.IsFalse(list.Enabled); 24 | } 25 | 26 | [Test] 27 | public void IsEnabledElement() 28 | { 29 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 30 | 31 | Assert.IsTrue(list.Enabled); 32 | } 33 | 34 | #endregion 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/IsElementSelectedTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public class IsElementSelectedTests : BaseForMainWindowTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void IsSelectedCheckBox() 17 | { 18 | var checkbox = this.MainWindow.FindElement(By.Id("CheckBox1")); 19 | 20 | Assert.IsTrue(checkbox.Selected); 21 | } 22 | 23 | [Test] 24 | public void IsSelectedListItem() 25 | { 26 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 27 | var listItem = list.FindElement(By.Name("May")); 28 | 29 | listItem.Click(); 30 | 31 | Assert.IsTrue(listItem.Selected); 32 | } 33 | 34 | [Test] 35 | public void IsSelectedTab() 36 | { 37 | var tab = this.MainWindow.FindElement(By.Name("TabItem1")); 38 | 39 | Assert.IsTrue(tab.Selected); 40 | } 41 | 42 | [Test] 43 | public void IsUnselectedCheckBox() 44 | { 45 | var checkbox = this.MainWindow.FindElement(By.Id("CheckBox1")); 46 | 47 | checkbox.Click(); 48 | 49 | Assert.IsFalse(checkbox.Selected); 50 | } 51 | 52 | [Test] 53 | public void IsUnselectedListItem() 54 | { 55 | var list = this.MainWindow.FindElement(By.Id("TextListBox")); 56 | var listItem = list.FindElement(By.Name("May")); 57 | 58 | Assert.IsFalse(listItem.Selected); 59 | } 60 | 61 | [Test] 62 | public void IsUnselectedTab() 63 | { 64 | var tab = this.MainWindow.FindElement(By.Name("TabItem2")); 65 | 66 | Assert.IsFalse(tab.Selected); 67 | } 68 | 69 | #endregion 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/MouseClickTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | using OpenQA.Selenium.Interactions; 9 | 10 | #endregion 11 | 12 | public class MouseClickTests : BaseForMainWindowTest 13 | { 14 | #region Fields 15 | 16 | private Actions action; 17 | 18 | private IWebElement button; 19 | 20 | private IWebElement textBox; 21 | 22 | #endregion 23 | 24 | #region Public Methods and Operators 25 | 26 | [Test] 27 | public void ClickToButton() 28 | { 29 | this.action.MoveToElement(this.button, 1, 1); 30 | this.action.Click(); 31 | this.action.Perform(); 32 | 33 | Assert.AreEqual("CARAMBA", this.textBox.Text); 34 | } 35 | 36 | [SetUp] 37 | public void SetUpForFindElementsAndCreateActionsClass() 38 | { 39 | this.textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 40 | this.button = this.MainWindow.FindElement(By.Id("SetTextButton")); 41 | 42 | this.action = new Actions(this.Driver); 43 | } 44 | 45 | #endregion 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/MouseDoubleClickTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium.Remote; 8 | 9 | #endregion 10 | 11 | public class MouseDoubleClickTests : BaseTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | [Ignore("Application not have needed elements")] 17 | public void ClickToButton() 18 | { 19 | // TODO: Extend WpfTestApplication 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/MouseMoveToTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using System.Windows; 6 | using System.Windows.Forms; 7 | 8 | using NUnit.Framework; 9 | 10 | using OpenQA.Selenium; 11 | using OpenQA.Selenium.Interactions; 12 | 13 | using Point = System.Drawing.Point; 14 | 15 | #endregion 16 | 17 | public class MouseMoveToTests : BaseForMainWindowTest 18 | { 19 | #region Constants 20 | 21 | private const int StartCrdValue = 10; 22 | 23 | #endregion 24 | 25 | #region Fields 26 | 27 | private Actions action; 28 | 29 | private IWebElement textBox; 30 | 31 | #endregion 32 | 33 | #region Public Methods and Operators 34 | 35 | [Test] 36 | public void MoveByOffset() 37 | { 38 | const int Offset = 50; 39 | 40 | this.action.MoveByOffset(Offset, Offset); 41 | this.action.Perform(); 42 | var newPoint = Cursor.Position; 43 | 44 | Assert.That(StartCrdValue + Offset, Is.EqualTo(newPoint.X).Within(1)); 45 | Assert.That(StartCrdValue + Offset, Is.EqualTo(newPoint.Y).Within(1)); 46 | } 47 | 48 | [Test] 49 | public void MoveToElementWithOffset() 50 | { 51 | const int Offset = 50; 52 | var rect = Rect.Parse(this.textBox.GetAttribute("BoundingRectangle")); 53 | 54 | this.action.MoveToElement(this.textBox, Offset, Offset); 55 | this.action.Perform(); 56 | var newPoint = Cursor.Position; 57 | 58 | Assert.That(rect.TopLeft.X + Offset, Is.EqualTo(newPoint.X).Within(1)); 59 | Assert.That(rect.TopLeft.Y + Offset, Is.EqualTo(newPoint.Y).Within(1)); 60 | } 61 | 62 | [Test] 63 | public void MoveToElementWithoutOffset() 64 | { 65 | var rect = Rect.Parse(this.textBox.GetAttribute("BoundingRectangle")); 66 | 67 | this.action.MoveToElement(this.textBox); 68 | this.action.Perform(); 69 | var newPoint = Cursor.Position; 70 | 71 | Assert.That(rect.TopLeft.X + (rect.Width / 2), Is.EqualTo(newPoint.X).Within(1)); 72 | Assert.That(rect.TopLeft.Y + (rect.Height / 2), Is.EqualTo(newPoint.Y).Within(1)); 73 | } 74 | 75 | [SetUp] 76 | public void SetUpForFindElementAndCreateActionsClass() 77 | { 78 | this.textBox = this.MainWindow.FindElement(By.Id("TextBox1")); 79 | this.action = new Actions(this.Driver); 80 | Cursor.Position = new Point(StartCrdValue, StartCrdValue); 81 | } 82 | 83 | #endregion 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/QuitTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using System.Diagnostics; 6 | 7 | using NUnit.Framework; 8 | 9 | using OpenQA.Selenium; 10 | 11 | #endregion 12 | 13 | [TestFixture] 14 | public class QuitTests 15 | { 16 | #region Fields 17 | 18 | private Process appProcess; 19 | 20 | private BaseForMainWindowTest baseForMainWindowTest; 21 | 22 | #endregion 23 | 24 | #region Public Methods and Operators 25 | 26 | [Test] 27 | public void CloseApplication() 28 | { 29 | this.baseForMainWindowTest.Driver.Quit(); 30 | 31 | Assert.IsTrue(this.appProcess.HasExited); 32 | } 33 | 34 | [Test] 35 | public void CloseApplicationWithOpenedDialogWindow() 36 | { 37 | this.baseForMainWindowTest.FindMainWindow(); 38 | var tabItem3 = this.baseForMainWindowTest.MainWindow.FindElement(By.Id("TabItem3")); 39 | tabItem3.Click(); 40 | tabItem3.FindElement(By.Id("OpenFileDialogButton")).Click(); 41 | 42 | this.baseForMainWindowTest.Driver.Quit(); 43 | 44 | Assert.IsTrue(this.appProcess.HasExited); 45 | } 46 | 47 | [SetUp] 48 | public void SetUp() 49 | { 50 | this.baseForMainWindowTest = new BaseForMainWindowTest(); 51 | this.baseForMainWindowTest.SetUp(); 52 | 53 | this.appProcess = Process.GetProcessesByName("WpfTestApplication")[0]; 54 | } 55 | 56 | #endregion 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/CommandTests/TakeScreenshotTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.CommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium.Remote; 8 | 9 | #endregion 10 | 11 | public class TakeScreenshotTests : BaseTest 12 | { 13 | #region Public Methods and Operators 14 | 15 | [Test] 16 | public void TakeScreenshotAfterStartApplication() 17 | { 18 | var screenshot = this.Driver.GetScreenshot().ToString(); 19 | Assert.That(screenshot.Length, Is.GreaterThan(0)); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region using 2 | 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | 6 | #endregion 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | [assembly: AssemblyTitle("WpfTestApplication.Tests")] 12 | [assembly: AssemblyDescription("")] 13 | [assembly: AssemblyConfiguration("")] 14 | [assembly: AssemblyCompany("")] 15 | [assembly: AssemblyProduct("WpfTestApplication.Tests")] 16 | [assembly: AssemblyCopyright("Copyright © 2015")] 17 | [assembly: AssemblyTrademark("")] 18 | [assembly: AssemblyCulture("")] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | [assembly: ComVisible(false)] 24 | 25 | // The following GUID is for the ID of the typelib if this project is exposed to COM 26 | [assembly: Guid("3b3aeff8-1b5e-4949-b663-650884293f80")] 27 | 28 | // Version information for an assembly consists of the following four values: 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.0.0.0")] 37 | [assembly: AssemblyFileVersion("1.0.0.0")] 38 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/TestHelper.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests 2 | { 3 | #region using 4 | 5 | using System.Reflection; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | public static class TestHelper 12 | { 13 | #region Public Methods and Operators 14 | 15 | public static string GetElementId(IWebElement element) 16 | { 17 | return 18 | element.GetType() 19 | .GetProperty("Id", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty) 20 | .GetValue(element, null) 21 | .ToString(); 22 | } 23 | 24 | #endregion 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/WiniumCommandTests/ComboBoxCommandsTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.WiniumCommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | [Ignore] 12 | public class ComboBoxCommandsTests : BaseTest 13 | { 14 | #region Public Properties 15 | 16 | public IWebElement ComboBoxElement { get; set; } 17 | 18 | #endregion 19 | 20 | #region Public Methods and Operators 21 | 22 | [Test] 23 | public void CollapseComboBox() 24 | { 25 | this.ComboBoxElement.Click(); 26 | 27 | this.Driver.CollapseComboBox(this.ComboBoxElement); 28 | 29 | Assert.IsFalse(this.ComboBoxElement.FindElement(By.Name("Month")).Displayed); 30 | } 31 | 32 | [Test] 33 | public void ExpandComboBox() 34 | { 35 | this.Driver.ExpandComboBox(this.ComboBoxElement); 36 | 37 | Assert.IsTrue(this.ComboBoxElement.FindElement(By.Name("Month")).Displayed); 38 | } 39 | 40 | [Test] 41 | public void ExpectNotSurchElementExceptionIfNoItemsSelected() 42 | { 43 | Assert.Throws(() => this.Driver.FindComboBoxSelctedItem(this.ComboBoxElement)); 44 | } 45 | 46 | [Test] 47 | public void FindSelectedItem() 48 | { 49 | this.ComboBoxElement.Click(); 50 | 51 | var item = this.ComboBoxElement.FindElement(By.Name("Month")); 52 | 53 | item.Click(); 54 | 55 | Assert.IsTrue(this.Driver.FindComboBoxSelctedItem(this.ComboBoxElement).Equals(item)); 56 | } 57 | 58 | [Test] 59 | public void IsComboBoxExpanded() 60 | { 61 | this.ComboBoxElement.Click(); 62 | 63 | Assert.IsTrue(this.Driver.IsComboBoxExpanded(this.ComboBoxElement)); 64 | } 65 | 66 | [SetUp] 67 | public new void SetUp() 68 | { 69 | var mainWindow = this.Driver.FindElement(By.XPath("/*[@AutomationId='WpfTestApplicationMainWindow']")); 70 | this.ComboBoxElement = mainWindow.FindElement(By.Id("TextComboBox")); 71 | } 72 | 73 | #endregion 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/WiniumCommandTests/DataGridCommandsTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.WiniumCommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | [Ignore] 12 | public class DataGridCommandsTests : BaseTest 13 | { 14 | #region Public Properties 15 | 16 | public IWebElement DataGridElement { get; set; } 17 | 18 | #endregion 19 | 20 | #region Public Methods and Operators 21 | 22 | [Test] 23 | public void ExpectNotSurchElementExceptionIfCellUnavailableForSelection() 24 | { 25 | Assert.Throws(() => this.Driver.SelectDataGridCell(this.DataGridElement, 14, 1)); 26 | } 27 | 28 | [Test] 29 | public void ExpectNotSurchElementExceptionIfDataGridCellNotExist() 30 | { 31 | Assert.Throws(() => this.Driver.FindDataGridCell(this.DataGridElement, 99, 9)); 32 | } 33 | 34 | [Test] 35 | public void ExpectNotSurchElementExceptionIfDataGridCellUnavailable() 36 | { 37 | Assert.Throws(() => this.Driver.FindDataGridCell(this.DataGridElement, 14, 1)); 38 | } 39 | 40 | [Test] 41 | public void FindDataGridCell() 42 | { 43 | var dataGridCell = this.Driver.FindDataGridCell(this.DataGridElement, 0, 1); 44 | 45 | Assert.AreEqual("one", dataGridCell.Text); 46 | } 47 | 48 | [Test] 49 | public void GetDataGridColumnCount() 50 | { 51 | var columnCount = this.Driver.GetDataGridColumnCount(this.DataGridElement); 52 | 53 | Assert.AreEqual(2, columnCount); 54 | } 55 | 56 | [Test] 57 | public void GetDataGridRowCount() 58 | { 59 | var rowCount = this.Driver.GetDataGridRowCount(this.DataGridElement); 60 | 61 | Assert.AreEqual(15, rowCount); 62 | } 63 | 64 | [Test] 65 | public void ScrollToDataGridCell() 66 | { 67 | this.Driver.ScrollToDataGridCell(this.DataGridElement, 14, 1); 68 | 69 | var dataGridCell = this.Driver.FindDataGridCell(this.DataGridElement, 14, 1); 70 | 71 | Assert.IsTrue(dataGridCell.Displayed); 72 | } 73 | 74 | [Test] 75 | public void SelectDataGridCell() 76 | { 77 | this.Driver.SelectDataGridCell(this.DataGridElement, 1, 1); 78 | var dataGridCell = this.Driver.FindDataGridCell(this.DataGridElement, 1, 1); 79 | 80 | var dataGridCellToo = this.Driver.SwitchTo().ActiveElement(); 81 | 82 | Assert.IsTrue(dataGridCell.Equals(dataGridCellToo)); 83 | } 84 | 85 | [SetUp] 86 | public new void SetUp() 87 | { 88 | var mainWindow = this.Driver.FindElement(By.XPath("/*[@AutomationId='WpfTestApplicationMainWindow']")); 89 | var tab = mainWindow.FindElement(By.Name("TabItem4")); 90 | tab.Click(); 91 | 92 | this.DataGridElement = tab.FindElement(By.Id("DataGrid")); 93 | } 94 | 95 | #endregion 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/WiniumCommandTests/MenuCommandsTests.cs: -------------------------------------------------------------------------------- 1 | namespace WpfTestApplication.Tests.WiniumCommandTests 2 | { 3 | #region using 4 | 5 | using NUnit.Framework; 6 | 7 | using OpenQA.Selenium; 8 | 9 | #endregion 10 | 11 | [Ignore] 12 | public class MenuCommandsTests : BaseTest 13 | { 14 | #region Public Properties 15 | 16 | public IWebElement MenuElement { get; set; } 17 | 18 | #endregion 19 | 20 | #region Public Methods and Operators 21 | 22 | [Test] 23 | public void ExpectNotSurchElementExceptionIfGetNotExistMenuItem() 24 | { 25 | Assert.Throws( 26 | () => this.Driver.FindMenuItem(this.MenuElement, "Level1$NotExistItem")); 27 | } 28 | 29 | [Test] 30 | public void ExpectNotSurchElementExceptionIfSelectNotExistMenuItem() 31 | { 32 | Assert.Throws( 33 | () => this.Driver.SelectMenuItem(this.MenuElement, "Level1$NotExistItem")); 34 | } 35 | 36 | [Test] 37 | public void FindMenuItem() 38 | { 39 | var menuItem = this.Driver.FindMenuItem(this.MenuElement, "Level1$MultiLevel2$Level3"); 40 | Assert.NotNull(menuItem); 41 | } 42 | 43 | [SetUp] 44 | public new void SetUp() 45 | { 46 | var mainWindow = this.Driver.FindElement(By.XPath("/*[@AutomationId='WpfTestApplicationMainWindow']")); 47 | this.MenuElement = mainWindow.FindElement(By.Id("SimpleMenu")); 48 | } 49 | 50 | #endregion 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/WpfTestApplication.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8B4DB0CD-0853-43A4-8E45-EB7080C1DCD7} 8 | Library 9 | Properties 10 | WpfTestApplication.Tests 11 | WpfTestApplication.Tests 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll 37 | True 38 | 39 | 40 | 41 | 42 | 43 | 44 | ..\..\packages\Selenium.WebDriver.2.53.1\lib\net40\WebDriver.dll 45 | True 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | Always 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 89 | 90 | 91 | 92 | 99 | -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/WpfTestApplication.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2gis/Winium.Desktop/bc4999ecc5c452839058a71054c685db8854f5c9/src/TestApps.Tests/WpfTestApplication.Tests/WpfTestApplication.exe -------------------------------------------------------------------------------- /src/TestApps.Tests/WpfTestApplication.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Automator/Automator.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.Automator 2 | { 3 | #region using 4 | 5 | using System.Collections.Generic; 6 | 7 | using Winium.Cruciatus; 8 | using Winium.Desktop.Driver.Input; 9 | 10 | #endregion 11 | 12 | internal class Automator 13 | { 14 | #region Static Fields 15 | 16 | private static readonly object LockObject = new object(); 17 | 18 | private static volatile Automator instance; 19 | 20 | #endregion 21 | 22 | #region Constructors and Destructors 23 | 24 | public Automator(string session) 25 | { 26 | this.Session = session; 27 | this.ElementsRegistry = new ElementsRegistry(); 28 | } 29 | 30 | #endregion 31 | 32 | #region Public Properties 33 | 34 | public Capabilities ActualCapabilities { get; set; } 35 | 36 | public Application Application { get; set; } 37 | 38 | public ElementsRegistry ElementsRegistry { get; private set; } 39 | 40 | public string Session { get; private set; } 41 | 42 | public WiniumKeyboard WiniumKeyboard { get; set; } 43 | 44 | #endregion 45 | 46 | #region Public Methods and Operators 47 | 48 | public static T GetValue(IReadOnlyDictionary parameters, string key) where T : class 49 | { 50 | object valueObject; 51 | parameters.TryGetValue(key, out valueObject); 52 | 53 | return valueObject as T; 54 | } 55 | 56 | public static Automator InstanceForSession(string sessionId) 57 | { 58 | if (instance == null) 59 | { 60 | lock (LockObject) 61 | { 62 | if (instance == null) 63 | { 64 | if (sessionId == null) 65 | { 66 | sessionId = "AwesomeSession"; 67 | } 68 | 69 | // TODO: Add actual support for sessions. Temporary return single Automator for any season 70 | instance = new Automator(sessionId); 71 | } 72 | } 73 | } 74 | 75 | return instance; 76 | } 77 | 78 | #endregion 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Automator/Capabilities.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.Automator 2 | { 3 | #region using 4 | 5 | using Newtonsoft.Json; 6 | using Newtonsoft.Json.Serialization; 7 | 8 | using Winium.Cruciatus.Settings; 9 | 10 | #endregion 11 | 12 | internal class Capabilities 13 | { 14 | #region Constructors and Destructors 15 | 16 | internal Capabilities() 17 | { 18 | this.App = string.Empty; 19 | this.Arguments = string.Empty; 20 | this.LaunchDelay = 0; 21 | this.DebugConnectToRunningApp = false; 22 | this.InnerPort = 9998; 23 | this.KeyboardSimulator = KeyboardSimulatorType.BasedOnInputSimulatorLib; 24 | } 25 | 26 | #endregion 27 | 28 | #region Public Properties 29 | 30 | [JsonProperty("app")] 31 | public string App { get; set; } 32 | 33 | [JsonProperty("args")] 34 | public string Arguments { get; set; } 35 | 36 | [JsonProperty("debugConnectToRunningApp")] 37 | public bool DebugConnectToRunningApp { get; set; } 38 | 39 | [JsonProperty("innerPort")] 40 | public int InnerPort { get; set; } 41 | 42 | [JsonProperty("keyboardSimulator")] 43 | public KeyboardSimulatorType KeyboardSimulator { get; set; } 44 | 45 | [JsonProperty("launchDelay")] 46 | public int LaunchDelay { get; set; } 47 | 48 | #endregion 49 | 50 | #region Public Methods and Operators 51 | 52 | public static Capabilities CapabilitiesFromJsonString(string jsonString) 53 | { 54 | var capabilities = JsonConvert.DeserializeObject( 55 | jsonString, 56 | new JsonSerializerSettings 57 | { 58 | Error = 59 | delegate(object sender, ErrorEventArgs args) 60 | { 61 | args.ErrorContext.Handled = true; 62 | } 63 | }); 64 | 65 | return capabilities; 66 | } 67 | 68 | public string CapabilitiesToJsonString() 69 | { 70 | return JsonConvert.SerializeObject(this); 71 | } 72 | 73 | #endregion 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutorDispatchTable.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Reflection; 9 | 10 | using Winium.Desktop.Driver.CommandExecutors; 11 | using Winium.StoreApps.Common; 12 | 13 | #endregion 14 | 15 | internal class CommandExecutorDispatchTable 16 | { 17 | #region Fields 18 | 19 | private Dictionary commandExecutorsRepository; 20 | 21 | #endregion 22 | 23 | #region Constructors and Destructors 24 | 25 | public CommandExecutorDispatchTable() 26 | { 27 | this.ConstructDispatcherTable(); 28 | } 29 | 30 | #endregion 31 | 32 | #region Public Methods and Operators 33 | 34 | public CommandExecutorBase GetExecutor(string commandName) 35 | { 36 | Type executorType; 37 | if (this.commandExecutorsRepository.TryGetValue(commandName, out executorType)) 38 | { 39 | } 40 | else 41 | { 42 | executorType = typeof(NotImplementedExecutor); 43 | } 44 | 45 | return (CommandExecutorBase)Activator.CreateInstance(executorType); 46 | } 47 | 48 | #endregion 49 | 50 | #region Methods 51 | 52 | private void ConstructDispatcherTable() 53 | { 54 | this.commandExecutorsRepository = new Dictionary(); 55 | 56 | // TODO: bad const 57 | const string ExecutorsNamespace = "Winium.Desktop.Driver.CommandExecutors"; 58 | 59 | var q = 60 | (from t in Assembly.GetExecutingAssembly().GetTypes() 61 | where t.IsClass && t.Namespace == ExecutorsNamespace 62 | select t).ToArray(); 63 | 64 | var fields = typeof(DriverCommand).GetFields(BindingFlags.Public | BindingFlags.Static); 65 | foreach (var field in fields) 66 | { 67 | var localField = field; 68 | var executor = q.FirstOrDefault(x => x.Name.Equals(localField.Name + "Executor")); 69 | if (executor != null) 70 | { 71 | this.commandExecutorsRepository.Add(localField.GetValue(null).ToString(), executor); 72 | } 73 | } 74 | } 75 | 76 | #endregion 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ClearElementExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | internal class ClearElementExecutor : CommandExecutorBase 4 | { 5 | #region Methods 6 | 7 | protected override string DoImpl() 8 | { 9 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 10 | 11 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 12 | element.SetText(null); 13 | 14 | return this.JsonResponse(); 15 | } 16 | 17 | #endregion 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ClickElementExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | internal class ClickElementExecutor : CommandExecutorBase 4 | { 5 | #region Methods 6 | 7 | protected override string DoImpl() 8 | { 9 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 10 | this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey).Click(); 11 | 12 | return this.JsonResponse(); 13 | } 14 | 15 | #endregion 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/CloseExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | internal class CloseExecutor : CommandExecutorBase 4 | { 5 | #region Methods 6 | 7 | protected override string DoImpl() 8 | { 9 | if (!this.Automator.ActualCapabilities.DebugConnectToRunningApp) 10 | { 11 | if (!this.Automator.Application.Close()) 12 | { 13 | this.Automator.Application.Kill(); 14 | } 15 | 16 | this.Automator.ElementsRegistry.Clear(); 17 | } 18 | 19 | return this.JsonResponse(); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/CollapseComboBoxExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Core; 6 | using Winium.Cruciatus.Extensions; 7 | using Winium.StoreApps.Common; 8 | 9 | #endregion 10 | 11 | internal class CollapseComboBoxExecutor : CommandExecutorBase 12 | { 13 | #region Methods 14 | 15 | protected override string DoImpl() 16 | { 17 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 18 | 19 | this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey).ToComboBox().Collapse(); 20 | 21 | return this.JsonResponse(); 22 | } 23 | 24 | #endregion 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/CommandExecutorBase.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.Net; 7 | 8 | using Newtonsoft.Json; 9 | 10 | using Winium.Desktop.Driver.Automator; 11 | using Winium.StoreApps.Common; 12 | using Winium.StoreApps.Common.Exceptions; 13 | 14 | #endregion 15 | 16 | internal abstract class CommandExecutorBase 17 | { 18 | #region Public Properties 19 | 20 | public Command ExecutedCommand { get; set; } 21 | 22 | #endregion 23 | 24 | #region Properties 25 | 26 | protected Automator Automator { get; set; } 27 | 28 | #endregion 29 | 30 | #region Public Methods and Operators 31 | 32 | public CommandResponse Do() 33 | { 34 | if (this.ExecutedCommand == null) 35 | { 36 | throw new NullReferenceException("ExecutedCommand property must be set before calling Do"); 37 | } 38 | 39 | try 40 | { 41 | var session = this.ExecutedCommand.SessionId; 42 | this.Automator = Automator.InstanceForSession(session); 43 | return CommandResponse.Create(HttpStatusCode.OK, this.DoImpl()); 44 | } 45 | catch (AutomationException exception) 46 | { 47 | return CommandResponse.Create(HttpStatusCode.OK, this.JsonResponse(exception.Status, exception)); 48 | } 49 | catch (NotImplementedException exception) 50 | { 51 | return CommandResponse.Create( 52 | HttpStatusCode.NotImplemented, 53 | this.JsonResponse(ResponseStatus.UnknownCommand, exception)); 54 | } 55 | catch (Exception exception) 56 | { 57 | return CommandResponse.Create( 58 | HttpStatusCode.OK, 59 | this.JsonResponse(ResponseStatus.UnknownError, exception)); 60 | } 61 | } 62 | 63 | #endregion 64 | 65 | #region Methods 66 | 67 | protected abstract string DoImpl(); 68 | 69 | /// 70 | /// The JsonResponse with SUCCESS status and NULL value. 71 | /// 72 | protected string JsonResponse() 73 | { 74 | return this.JsonResponse(ResponseStatus.Success, null); 75 | } 76 | 77 | protected string JsonResponse(ResponseStatus status, object value) 78 | { 79 | return JsonConvert.SerializeObject( 80 | new JsonResponse(this.Automator.Session, status, value), 81 | Formatting.Indented); 82 | } 83 | 84 | #endregion 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ElementEqualsExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.StoreApps.Common; 6 | 7 | #endregion 8 | 9 | internal class ElementEqualsExecutor : CommandExecutorBase 10 | { 11 | #region Methods 12 | 13 | protected override string DoImpl() 14 | { 15 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 16 | var otherRegisteredKey = this.ExecutedCommand.Parameters["other"].ToString(); 17 | 18 | return this.JsonResponse(ResponseStatus.Success, registeredKey == otherRegisteredKey); 19 | } 20 | 21 | #endregion 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ExecuteScriptExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Windows.Automation; 8 | 9 | using Newtonsoft.Json.Linq; 10 | 11 | using Winium.Cruciatus.Core; 12 | using Winium.Cruciatus.Elements; 13 | using Winium.Cruciatus.Extensions; 14 | using Winium.StoreApps.Common; 15 | using Winium.StoreApps.Common.Exceptions; 16 | 17 | #endregion 18 | 19 | internal class ExecuteScriptExecutor : CommandExecutorBase 20 | { 21 | #region Constants 22 | 23 | internal const string HelpArgumentsErrorMsg = "Arguments error. See {0} for more information."; 24 | 25 | internal const string HelpUnknownScriptMsg = "Unknown script command '{0} {1}'. See {2} for supported commands."; 26 | 27 | internal const string HelpUrlAutomationScript = 28 | "https://github.com/2gis/Winium.Desktop/wiki/Command-Execute-Script#use-ui-automation-patterns-on-element"; 29 | 30 | internal const string HelpUrlInputScript = 31 | "https://github.com/2gis/Winium.Desktop/wiki/Command-Execute-Script#simulate-input"; 32 | 33 | internal const string HelpUrlScript = "https://github.com/2gis/Winium.Desktop/wiki/Command-Execute-Script"; 34 | 35 | #endregion 36 | 37 | #region Methods 38 | 39 | protected override string DoImpl() 40 | { 41 | var script = this.ExecutedCommand.Parameters["script"].ToString(); 42 | 43 | var prefix = string.Empty; 44 | string command; 45 | 46 | var index = script.IndexOf(':'); 47 | if (index == -1) 48 | { 49 | command = script; 50 | } 51 | else 52 | { 53 | prefix = script.Substring(0, index); 54 | command = script.Substring(++index).Trim(); 55 | } 56 | 57 | switch (prefix) 58 | { 59 | case "input": 60 | this.ExecuteInputScript(command); 61 | break; 62 | case "automation": 63 | this.ExecuteAutomationScript(command); 64 | break; 65 | default: 66 | var msg = string.Format(HelpUnknownScriptMsg, prefix, command, HelpUrlScript); 67 | throw new AutomationException(msg, ResponseStatus.JavaScriptError); 68 | } 69 | 70 | return this.JsonResponse(); 71 | } 72 | 73 | private void ExecuteAutomationScript(string command) 74 | { 75 | var args = (JArray)this.ExecutedCommand.Parameters["args"]; 76 | var elementId = args[0]["ELEMENT"].ToString(); 77 | 78 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(elementId); 79 | 80 | switch (command) 81 | { 82 | case "ValuePattern.SetValue": 83 | this.ValuePatternSetValue(element, args); 84 | break; 85 | default: 86 | var msg = string.Format(HelpUnknownScriptMsg, "automation:", command, HelpUrlAutomationScript); 87 | throw new AutomationException(msg, ResponseStatus.JavaScriptError); 88 | } 89 | } 90 | 91 | private void ExecuteInputScript(string command) 92 | { 93 | var args = (JArray)this.ExecutedCommand.Parameters["args"]; 94 | var elementId = args[0]["ELEMENT"].ToString(); 95 | 96 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(elementId); 97 | 98 | switch (command) 99 | { 100 | case "ctrl_click": 101 | element.ClickWithPressedCtrl(); 102 | return; 103 | case "brc_click": 104 | element.Click(MouseButton.Left, ClickStrategies.BoundingRectangleCenter); 105 | return; 106 | default: 107 | var msg = string.Format(HelpUnknownScriptMsg, "input:", command, HelpUrlInputScript); 108 | throw new AutomationException(msg, ResponseStatus.JavaScriptError); 109 | } 110 | } 111 | 112 | private void ValuePatternSetValue(CruciatusElement element, IEnumerable args) 113 | { 114 | var value = args.ElementAtOrDefault(1); 115 | if (value == null) 116 | { 117 | var msg = string.Format(HelpArgumentsErrorMsg, HelpUrlAutomationScript); 118 | throw new AutomationException(msg, ResponseStatus.JavaScriptError); 119 | } 120 | 121 | element.GetPattern(ValuePattern.Pattern).SetValue(value.ToString()); 122 | } 123 | 124 | #endregion 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ExpandComboBoxExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Core; 6 | using Winium.Cruciatus.Extensions; 7 | using Winium.StoreApps.Common; 8 | 9 | #endregion 10 | 11 | internal class ExpandComboBoxExecutor : CommandExecutorBase 12 | { 13 | #region Methods 14 | 15 | protected override string DoImpl() 16 | { 17 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 18 | 19 | this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey).ToComboBox().Expand(); 20 | 21 | return this.JsonResponse(); 22 | } 23 | 24 | #endregion 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/FindChildElementExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Desktop.Driver.Extensions; 6 | using Winium.StoreApps.Common; 7 | using Winium.StoreApps.Common.Exceptions; 8 | 9 | #endregion 10 | 11 | internal class FindChildElementExecutor : CommandExecutorBase 12 | { 13 | #region Methods 14 | 15 | protected override string DoImpl() 16 | { 17 | var parentKey = this.ExecutedCommand.Parameters["ID"].ToString(); 18 | var searchValue = this.ExecutedCommand.Parameters["value"].ToString(); 19 | var searchStrategy = this.ExecutedCommand.Parameters["using"].ToString(); 20 | 21 | var parent = this.Automator.ElementsRegistry.GetRegisteredElement(parentKey); 22 | var strategy = ByHelper.GetStrategy(searchStrategy, searchValue); 23 | var element = parent.FindElement(strategy); 24 | if (element == null) 25 | { 26 | throw new AutomationException("Element cannot be found", ResponseStatus.NoSuchElement); 27 | } 28 | 29 | var registeredKey = this.Automator.ElementsRegistry.RegisterElement(element); 30 | var registeredObject = new JsonElementContent(registeredKey); 31 | return this.JsonResponse(ResponseStatus.Success, registeredObject); 32 | } 33 | 34 | #endregion 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/FindChildElementsExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Linq; 6 | 7 | using Winium.Desktop.Driver.Extensions; 8 | using Winium.StoreApps.Common; 9 | 10 | #endregion 11 | 12 | internal class FindChildElementsExecutor : CommandExecutorBase 13 | { 14 | #region Methods 15 | 16 | protected override string DoImpl() 17 | { 18 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 19 | var searchValue = this.ExecutedCommand.Parameters["value"].ToString(); 20 | var searchStrategy = this.ExecutedCommand.Parameters["using"].ToString(); 21 | 22 | var parent = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 23 | var strategy = ByHelper.GetStrategy(searchStrategy, searchValue); 24 | var elements = parent.FindElements(strategy); 25 | 26 | var registeredKeys = this.Automator.ElementsRegistry.RegisterElements(elements); 27 | var registeredObjects = registeredKeys.Select(e => new JsonElementContent(e)); 28 | return this.JsonResponse(ResponseStatus.Success, registeredObjects); 29 | } 30 | 31 | #endregion 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/FindComboBoxSelectedItemExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Extensions; 6 | using Winium.StoreApps.Common; 7 | using Winium.StoreApps.Common.Exceptions; 8 | 9 | #endregion 10 | 11 | internal class FindComboBoxSelectedItemExecutor : CommandExecutorBase 12 | { 13 | #region Methods 14 | 15 | protected override string DoImpl() 16 | { 17 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 18 | 19 | var comboBox = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey).ToComboBox(); 20 | 21 | var selectedItem = comboBox.SelectedItem(); 22 | if (selectedItem == null) 23 | { 24 | throw new AutomationException("No items is selected", ResponseStatus.NoSuchElement); 25 | } 26 | 27 | var selectedItemKey = this.Automator.ElementsRegistry.RegisterElement(selectedItem); 28 | var registeredObject = new JsonElementContent(selectedItemKey); 29 | 30 | return this.JsonResponse(ResponseStatus.Success, registeredObject); 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/FindDataGridCellExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Elements; 6 | using Winium.Cruciatus.Exceptions; 7 | using Winium.Cruciatus.Extensions; 8 | using Winium.StoreApps.Common; 9 | 10 | #endregion 11 | 12 | internal class FindDataGridCellExecutor : CommandExecutorBase 13 | { 14 | #region Methods 15 | 16 | protected override string DoImpl() 17 | { 18 | var dataGridKey = this.ExecutedCommand.Parameters["ID"].ToString(); 19 | var column = int.Parse(this.ExecutedCommand.Parameters["COLUMN"].ToString()); 20 | var row = int.Parse(this.ExecutedCommand.Parameters["ROW"].ToString()); 21 | 22 | var dataGrid = this.Automator.ElementsRegistry.GetRegisteredElement(dataGridKey).ToDataGrid(); 23 | 24 | CruciatusElement dataGridCell; 25 | try 26 | { 27 | dataGridCell = dataGrid.Item(row, column); 28 | } 29 | catch (CruciatusException exception) 30 | { 31 | return this.JsonResponse(ResponseStatus.NoSuchElement, exception); 32 | } 33 | 34 | var registeredKey = this.Automator.ElementsRegistry.RegisterElement(dataGridCell); 35 | var registeredObject = new JsonElementContent(registeredKey); 36 | 37 | return this.JsonResponse(ResponseStatus.Success, registeredObject); 38 | } 39 | 40 | #endregion 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/FindElementExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus; 6 | using Winium.Desktop.Driver.Extensions; 7 | using Winium.StoreApps.Common; 8 | using Winium.StoreApps.Common.Exceptions; 9 | 10 | #endregion 11 | 12 | internal class FindElementExecutor : CommandExecutorBase 13 | { 14 | #region Methods 15 | 16 | protected override string DoImpl() 17 | { 18 | var searchValue = this.ExecutedCommand.Parameters["value"].ToString(); 19 | var searchStrategy = this.ExecutedCommand.Parameters["using"].ToString(); 20 | 21 | var strategy = ByHelper.GetStrategy(searchStrategy, searchValue); 22 | var element = CruciatusFactory.Root.FindElement(strategy); 23 | if (element == null) 24 | { 25 | throw new AutomationException("Element cannot be found", ResponseStatus.NoSuchElement); 26 | } 27 | 28 | var registeredKey = this.Automator.ElementsRegistry.RegisterElement(element); 29 | var registeredObject = new JsonElementContent(registeredKey); 30 | return this.JsonResponse(ResponseStatus.Success, registeredObject); 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/FindElementsExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Linq; 6 | 7 | using Winium.Cruciatus; 8 | using Winium.Desktop.Driver.Extensions; 9 | using Winium.StoreApps.Common; 10 | 11 | #endregion 12 | 13 | internal class FindElementsExecutor : CommandExecutorBase 14 | { 15 | #region Methods 16 | 17 | protected override string DoImpl() 18 | { 19 | var searchValue = this.ExecutedCommand.Parameters["value"].ToString(); 20 | var searchStrategy = this.ExecutedCommand.Parameters["using"].ToString(); 21 | 22 | var strategy = ByHelper.GetStrategy(searchStrategy, searchValue); 23 | var elements = CruciatusFactory.Root.FindElements(strategy); 24 | 25 | var registeredKeys = this.Automator.ElementsRegistry.RegisterElements(elements); 26 | var registeredObjects = registeredKeys.Select(e => new JsonElementContent(e)); 27 | return this.JsonResponse(ResponseStatus.Success, registeredObjects); 28 | } 29 | 30 | #endregion 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/FindMenuItemExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Extensions; 6 | using Winium.StoreApps.Common; 7 | using Winium.StoreApps.Common.Exceptions; 8 | 9 | #endregion 10 | 11 | internal class FindMenuItemExecutor : CommandExecutorBase 12 | { 13 | #region Methods 14 | 15 | protected override string DoImpl() 16 | { 17 | var dataGridKey = this.ExecutedCommand.Parameters["ID"].ToString(); 18 | var headersPath = this.ExecutedCommand.Parameters["PATH"].ToString(); 19 | 20 | var munu = this.Automator.ElementsRegistry.GetRegisteredElement(dataGridKey).ToMenu(); 21 | 22 | var element = munu.GetItem(headersPath); 23 | if (element == null) 24 | { 25 | throw new AutomationException("No menu item was found", ResponseStatus.NoSuchElement); 26 | } 27 | 28 | var elementKey = this.Automator.ElementsRegistry.RegisterElement(element); 29 | 30 | return this.JsonResponse(ResponseStatus.Success, new JsonElementContent(elementKey)); 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/GetActiveElementExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus; 6 | using Winium.StoreApps.Common; 7 | 8 | #endregion 9 | 10 | internal class GetActiveElementExecutor : CommandExecutorBase 11 | { 12 | #region Methods 13 | 14 | protected override string DoImpl() 15 | { 16 | var registeredKey = this.Automator.ElementsRegistry.RegisterElement(CruciatusFactory.FocusedElement); 17 | var registeredObject = new JsonElementContent(registeredKey); 18 | return this.JsonResponse(ResponseStatus.Success, registeredObject); 19 | } 20 | 21 | #endregion 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/GetCurrentWindowHandleExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Globalization; 6 | using System.Windows.Automation; 7 | 8 | using Winium.StoreApps.Common; 9 | 10 | #endregion 11 | 12 | internal class GetCurrentWindowHandleExecutor : CommandExecutorBase 13 | { 14 | #region Methods 15 | 16 | protected override string DoImpl() 17 | { 18 | var node = AutomationElement.FocusedElement; 19 | var rootElement = AutomationElement.RootElement; 20 | var treeWalker = TreeWalker.ControlViewWalker; 21 | while (node != rootElement && !node.Current.ControlType.Equals(ControlType.Window)) 22 | { 23 | node = treeWalker.GetParent(node); 24 | } 25 | 26 | var result = (node == rootElement) 27 | ? string.Empty 28 | : node.Current.NativeWindowHandle.ToString(CultureInfo.InvariantCulture); 29 | return this.JsonResponse(ResponseStatus.Success, result); 30 | } 31 | 32 | #endregion 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/GetDataGridColumnCountExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Extensions; 6 | using Winium.StoreApps.Common; 7 | 8 | #endregion 9 | 10 | internal class GetDataGridColumnCountExecutor : CommandExecutorBase 11 | { 12 | #region Methods 13 | 14 | protected override string DoImpl() 15 | { 16 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 17 | 18 | var dataGrid = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey).ToDataGrid(); 19 | 20 | return this.JsonResponse(ResponseStatus.Success, dataGrid.ColumnCount); 21 | } 22 | 23 | #endregion 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/GetDataGridRowCountExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Extensions; 6 | using Winium.StoreApps.Common; 7 | 8 | #endregion 9 | 10 | internal class GetDataGridRowCountExecutor : CommandExecutorBase 11 | { 12 | #region Methods 13 | 14 | protected override string DoImpl() 15 | { 16 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 17 | 18 | var dataGrid = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey).ToDataGrid(); 19 | 20 | return this.JsonResponse(ResponseStatus.Success, dataGrid.RowCount); 21 | } 22 | 23 | #endregion 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/GetElementAttributeExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.Windows.Automation; 7 | 8 | using Winium.Cruciatus.Extensions; 9 | using Winium.Desktop.Driver.Extensions; 10 | using Winium.StoreApps.Common; 11 | 12 | #endregion 13 | 14 | internal class GetElementAttributeExecutor : CommandExecutorBase 15 | { 16 | #region Methods 17 | 18 | protected override string DoImpl() 19 | { 20 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 21 | var propertyName = this.ExecutedCommand.Parameters["NAME"].ToString(); 22 | 23 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 24 | 25 | try 26 | { 27 | var property = AutomationPropertyHelper.GetAutomationProperty(propertyName); 28 | var propertyObject = element.GetAutomationPropertyValue(property); 29 | 30 | return this.JsonResponse(ResponseStatus.Success, PrepareValueToSerialize(propertyObject)); 31 | } 32 | catch (Exception) 33 | { 34 | return this.JsonResponse(); 35 | } 36 | } 37 | 38 | /* Known types: 39 | * string, bool, int - should be as plain text 40 | * System.Windows.Automation.ControlType - should be used `ProgrammaticName` property 41 | * System.Window.Rect, System.Window.Point - overrides `ToString()` method, can serialize 42 | */ 43 | private static object PrepareValueToSerialize(object obj) 44 | { 45 | if (obj == null) 46 | { 47 | return null; 48 | } 49 | 50 | if (obj.GetType().IsPrimitive) 51 | { 52 | return obj.ToString(); 53 | } 54 | 55 | var controlType = obj as ControlType; 56 | if (controlType != null) 57 | { 58 | return controlType.ProgrammaticName; 59 | } 60 | 61 | return obj; 62 | } 63 | 64 | #endregion 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/GetElementSizeExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Collections.Generic; 6 | 7 | using Winium.StoreApps.Common; 8 | 9 | #endregion 10 | 11 | internal class GetElementSizeExecutor : CommandExecutorBase 12 | { 13 | #region Methods 14 | 15 | protected override string DoImpl() 16 | { 17 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 18 | 19 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 20 | 21 | var boundingRect = element.Properties.BoundingRectangle; 22 | 23 | var response = new Dictionary 24 | { 25 | { "width", boundingRect.Width }, 26 | { "height", boundingRect.Height } 27 | }; 28 | return this.JsonResponse(ResponseStatus.Success, response); 29 | } 30 | 31 | #endregion 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/GetElementTextExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.StoreApps.Common; 6 | 7 | #endregion 8 | 9 | internal class GetElementTextExecutor : CommandExecutorBase 10 | { 11 | #region Methods 12 | 13 | protected override string DoImpl() 14 | { 15 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 16 | 17 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 18 | 19 | return this.JsonResponse(ResponseStatus.Success, element.Text()); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/GetOrientationExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Core; 6 | using Winium.StoreApps.Common; 7 | 8 | #endregion 9 | 10 | internal class GetOrientationExecutor : CommandExecutorBase 11 | { 12 | #region Methods 13 | 14 | protected override string DoImpl() 15 | { 16 | var orientation = RotationManager.GetCurrentOrientation(); 17 | 18 | return this.JsonResponse(ResponseStatus.Success, orientation.ToString()); 19 | } 20 | 21 | #endregion 22 | } 23 | } -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/GetWindowHandlesExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Linq; 6 | using System.Windows.Automation; 7 | 8 | using Winium.Cruciatus; 9 | using Winium.Cruciatus.Core; 10 | using Winium.Cruciatus.Extensions; 11 | using Winium.StoreApps.Common; 12 | 13 | #endregion 14 | 15 | internal class GetWindowHandlesExecutor : CommandExecutorBase 16 | { 17 | #region Methods 18 | 19 | protected override string DoImpl() 20 | { 21 | var typeProperty = AutomationElement.ControlTypeProperty; 22 | var windows = CruciatusFactory.Root.FindElements(By.AutomationProperty(typeProperty, ControlType.Window)); 23 | 24 | var handleProperty = AutomationElement.NativeWindowHandleProperty; 25 | var handles = windows.Select(element => element.GetAutomationPropertyValue(handleProperty)); 26 | 27 | return this.JsonResponse(ResponseStatus.Success, handles); 28 | } 29 | 30 | #endregion 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ImplicitlyWaitExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System; 6 | 7 | using Winium.Cruciatus; 8 | using Winium.StoreApps.Common; 9 | 10 | #endregion 11 | 12 | internal class ImplicitlyWaitExecutor : CommandExecutorBase 13 | { 14 | #region Methods 15 | 16 | protected override string DoImpl() 17 | { 18 | var timeout = this.ExecutedCommand.Parameters["ms"]; 19 | 20 | CruciatusFactory.Settings.SearchTimeout = Convert.ToInt32(timeout); 21 | 22 | return this.JsonResponse(); 23 | } 24 | 25 | #endregion 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/IsComboBoxExpandedExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Extensions; 6 | using Winium.StoreApps.Common; 7 | 8 | #endregion 9 | 10 | internal class IsComboBoxExpandedExecutor : CommandExecutorBase 11 | { 12 | #region Methods 13 | 14 | protected override string DoImpl() 15 | { 16 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 17 | 18 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 19 | 20 | return this.JsonResponse(ResponseStatus.Success, element.ToComboBox().IsExpanded); 21 | } 22 | 23 | #endregion 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/IsElementDisplayedExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.StoreApps.Common; 6 | 7 | #endregion 8 | 9 | internal class IsElementDisplayedExecutor : CommandExecutorBase 10 | { 11 | #region Methods 12 | 13 | protected override string DoImpl() 14 | { 15 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 16 | 17 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 18 | 19 | return this.JsonResponse(ResponseStatus.Success, !element.Properties.IsOffscreen); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/IsElementEnabledExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.StoreApps.Common; 6 | 7 | #endregion 8 | 9 | internal class IsElementEnabledExecutor : CommandExecutorBase 10 | { 11 | #region Methods 12 | 13 | protected override string DoImpl() 14 | { 15 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 16 | 17 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 18 | 19 | return this.JsonResponse(ResponseStatus.Success, element.Properties.IsEnabled); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/IsElementSelectedExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Windows.Automation; 6 | 7 | using Winium.Cruciatus.Exceptions; 8 | using Winium.Cruciatus.Extensions; 9 | using Winium.StoreApps.Common; 10 | 11 | #endregion 12 | 13 | internal class IsElementSelectedExecutor : CommandExecutorBase 14 | { 15 | #region Methods 16 | 17 | protected override string DoImpl() 18 | { 19 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 20 | 21 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 22 | 23 | bool isSelected; 24 | 25 | try 26 | { 27 | var selectionItemProperty = SelectionItemPattern.IsSelectedProperty; 28 | isSelected = element.GetAutomationPropertyValue(selectionItemProperty); 29 | } 30 | catch (CruciatusException) 31 | { 32 | var toggleStateProperty = TogglePattern.ToggleStateProperty; 33 | var toggleState = element.GetAutomationPropertyValue(toggleStateProperty); 34 | 35 | isSelected = toggleState == ToggleState.On; 36 | } 37 | 38 | return this.JsonResponse(ResponseStatus.Success, isSelected); 39 | } 40 | 41 | #endregion 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/MouseClickExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System; 6 | 7 | using Winium.Cruciatus; 8 | using Winium.Cruciatus.Core; 9 | using Winium.StoreApps.Common; 10 | 11 | #endregion 12 | 13 | internal class MouseClickExecutor : CommandExecutorBase 14 | { 15 | #region Methods 16 | 17 | protected override string DoImpl() 18 | { 19 | var buttonId = Convert.ToInt32(this.ExecutedCommand.Parameters["button"]); 20 | 21 | switch ((MouseButton)buttonId) 22 | { 23 | case MouseButton.Left: 24 | CruciatusFactory.Mouse.LeftButtonClick(); 25 | break; 26 | 27 | case MouseButton.Right: 28 | CruciatusFactory.Mouse.RightButtonClick(); 29 | break; 30 | 31 | default: 32 | return this.JsonResponse(ResponseStatus.UnknownCommand, "Mouse button behavior is not implemented"); 33 | } 34 | 35 | return this.JsonResponse(); 36 | } 37 | 38 | #endregion 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/MouseDoubleClickExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus; 6 | using Winium.Cruciatus.Core; 7 | 8 | #endregion 9 | 10 | internal class MouseDoubleClickExecutor : CommandExecutorBase 11 | { 12 | #region Methods 13 | 14 | protected override string DoImpl() 15 | { 16 | CruciatusFactory.Mouse.DoubleClick(MouseButton.Left); 17 | return this.JsonResponse(); 18 | } 19 | 20 | #endregion 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/MouseMoveToExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System; 6 | 7 | using Winium.Cruciatus; 8 | using Winium.StoreApps.Common; 9 | 10 | #endregion 11 | 12 | internal class MouseMoveToExecutor : CommandExecutorBase 13 | { 14 | #region Methods 15 | 16 | protected override string DoImpl() 17 | { 18 | var haveElement = this.ExecutedCommand.Parameters.ContainsKey("element"); 19 | var haveOffset = this.ExecutedCommand.Parameters.ContainsKey("xoffset") 20 | && this.ExecutedCommand.Parameters.ContainsKey("yoffset"); 21 | 22 | if (!(haveElement || haveOffset)) 23 | { 24 | // TODO: in the future '400 : invalid argument' will be used 25 | return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); 26 | } 27 | 28 | var resultPoint = CruciatusFactory.Mouse.CurrentCursorPos; 29 | if (haveElement) 30 | { 31 | var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); 32 | var element = this.Automator.ElementsRegistry.GetRegisteredElementOrNull(registeredKey); 33 | if (element != null) 34 | { 35 | var rect = element.Properties.BoundingRectangle; 36 | resultPoint.X = rect.TopLeft.X; 37 | resultPoint.Y = rect.TopLeft.Y; 38 | if (!haveOffset) 39 | { 40 | resultPoint.X += rect.Width / 2; 41 | resultPoint.Y += rect.Height / 2; 42 | } 43 | } 44 | } 45 | 46 | if (haveOffset) 47 | { 48 | resultPoint.X += Convert.ToInt32(this.ExecutedCommand.Parameters["xoffset"]); 49 | resultPoint.Y += Convert.ToInt32(this.ExecutedCommand.Parameters["yoffset"]); 50 | } 51 | 52 | CruciatusFactory.Mouse.SetCursorPos(resultPoint.X, resultPoint.Y); 53 | 54 | return this.JsonResponse(); 55 | } 56 | 57 | #endregion 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/NewSessionExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Threading; 6 | 7 | using Newtonsoft.Json; 8 | 9 | using Winium.Cruciatus; 10 | using Winium.Cruciatus.Settings; 11 | using Winium.Desktop.Driver.Automator; 12 | using Winium.Desktop.Driver.Input; 13 | using Winium.StoreApps.Common; 14 | 15 | #endregion 16 | 17 | internal class NewSessionExecutor : CommandExecutorBase 18 | { 19 | #region Methods 20 | 21 | protected override string DoImpl() 22 | { 23 | // It is easier to reparse desired capabilities as JSON instead of re-mapping keys to attributes and calling type conversions, 24 | // so we will take possible one time performance hit by serializing Dictionary and deserializing it as Capabilities object 25 | var serializedCapability = 26 | JsonConvert.SerializeObject(this.ExecutedCommand.Parameters["desiredCapabilities"]); 27 | this.Automator.ActualCapabilities = Capabilities.CapabilitiesFromJsonString(serializedCapability); 28 | 29 | this.InitializeApplication(this.Automator.ActualCapabilities.DebugConnectToRunningApp); 30 | this.InitializeKeyboardEmulator(this.Automator.ActualCapabilities.KeyboardSimulator); 31 | 32 | // Gives sometime to load visuals (needed only in case of slow emulation) 33 | Thread.Sleep(this.Automator.ActualCapabilities.LaunchDelay); 34 | 35 | return this.JsonResponse(ResponseStatus.Success, this.Automator.ActualCapabilities); 36 | } 37 | 38 | private void InitializeApplication(bool debugDoNotDeploy = false) 39 | { 40 | var appPath = this.Automator.ActualCapabilities.App; 41 | var appArguments = this.Automator.ActualCapabilities.Arguments; 42 | 43 | this.Automator.Application = new Application(appPath); 44 | if (!debugDoNotDeploy) 45 | { 46 | this.Automator.Application.Start(appArguments); 47 | } 48 | } 49 | 50 | private void InitializeKeyboardEmulator(KeyboardSimulatorType keyboardSimulatorType) 51 | { 52 | this.Automator.WiniumKeyboard = new WiniumKeyboard(keyboardSimulatorType); 53 | 54 | Logger.Debug("Current keyboard simulator: {0}", keyboardSimulatorType); 55 | } 56 | 57 | #endregion 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/NotImplementedExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System; 6 | 7 | #endregion 8 | 9 | internal class NotImplementedExecutor : CommandExecutorBase 10 | { 11 | #region Methods 12 | 13 | protected override string DoImpl() 14 | { 15 | var msg = string.Format("'{0}' is not valid or implemented command.", this.ExecutedCommand.Name); 16 | throw new NotImplementedException(msg); 17 | } 18 | 19 | #endregion 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/QuitExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | internal class QuitExecutor : CommandExecutorBase 4 | { 5 | #region Methods 6 | 7 | protected override string DoImpl() 8 | { 9 | if (!this.Automator.ActualCapabilities.DebugConnectToRunningApp) 10 | { 11 | if (!this.Automator.Application.Close()) 12 | { 13 | this.Automator.Application.Kill(); 14 | } 15 | 16 | this.Automator.ElementsRegistry.Clear(); 17 | } 18 | 19 | return this.JsonResponse(); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ScreenshotExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus; 6 | using Winium.StoreApps.Common; 7 | 8 | #endregion 9 | 10 | internal class ScreenshotExecutor : CommandExecutorBase 11 | { 12 | #region Methods 13 | 14 | protected override string DoImpl() 15 | { 16 | var screenshot = CruciatusFactory.Screenshoter.GetScreenshot(); 17 | var screenshotSource = screenshot.AsBase64String(); 18 | 19 | return this.JsonResponse(ResponseStatus.Success, screenshotSource); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ScrollToComboBoxItemExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Elements; 6 | using Winium.Cruciatus.Exceptions; 7 | using Winium.Cruciatus.Extensions; 8 | using Winium.Desktop.Driver.Extensions; 9 | using Winium.StoreApps.Common; 10 | 11 | #endregion 12 | 13 | internal class ScrollToComboBoxItemExecutor : CommandExecutorBase 14 | { 15 | #region Methods 16 | 17 | protected override string DoImpl() 18 | { 19 | var dataGridKey = this.ExecutedCommand.Parameters["ID"].ToString(); 20 | var searchStrategy = this.ExecutedCommand.Parameters["using"].ToString(); 21 | var searchValue = this.ExecutedCommand.Parameters["value"].ToString(); 22 | 23 | var strategy = ByHelper.GetStrategy(searchStrategy, searchValue); 24 | 25 | var comboBox = this.Automator.ElementsRegistry.GetRegisteredElement(dataGridKey).ToComboBox(); 26 | 27 | CruciatusElement element; 28 | try 29 | { 30 | element = comboBox.ScrollTo(strategy); 31 | } 32 | catch (CruciatusException exception) 33 | { 34 | return this.JsonResponse(ResponseStatus.NoSuchElement, exception); 35 | } 36 | 37 | var elementKey = this.Automator.ElementsRegistry.RegisterElement(element); 38 | 39 | return this.JsonResponse(ResponseStatus.Success, new JsonElementContent(elementKey)); 40 | } 41 | 42 | #endregion 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ScrollToDataGridCellExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Exceptions; 6 | using Winium.Cruciatus.Extensions; 7 | using Winium.StoreApps.Common; 8 | 9 | #endregion 10 | 11 | internal class ScrollToDataGridCellExecutor : CommandExecutorBase 12 | { 13 | #region Methods 14 | 15 | protected override string DoImpl() 16 | { 17 | var dataGridKey = this.ExecutedCommand.Parameters["ID"].ToString(); 18 | var column = int.Parse(this.ExecutedCommand.Parameters["COLUMN"].ToString()); 19 | var row = int.Parse(this.ExecutedCommand.Parameters["ROW"].ToString()); 20 | 21 | var dataGrid = this.Automator.ElementsRegistry.GetRegisteredElement(dataGridKey).ToDataGrid(); 22 | 23 | try 24 | { 25 | dataGrid.ScrollTo(row, column); 26 | } 27 | catch (CruciatusException exception) 28 | { 29 | return this.JsonResponse(ResponseStatus.NoSuchElement, exception); 30 | } 31 | 32 | return this.JsonResponse(); 33 | } 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/ScrollToListBoxItemExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Elements; 6 | using Winium.Cruciatus.Exceptions; 7 | using Winium.Cruciatus.Extensions; 8 | using Winium.Desktop.Driver.Extensions; 9 | using Winium.StoreApps.Common; 10 | 11 | #endregion 12 | 13 | internal class ScrollToListBoxItemExecutor : CommandExecutorBase 14 | { 15 | #region Methods 16 | 17 | protected override string DoImpl() 18 | { 19 | var dataGridKey = this.ExecutedCommand.Parameters["ID"].ToString(); 20 | var searchStrategy = this.ExecutedCommand.Parameters["using"].ToString(); 21 | var searchValue = this.ExecutedCommand.Parameters["value"].ToString(); 22 | 23 | var strategy = ByHelper.GetStrategy(searchStrategy, searchValue); 24 | 25 | var listBox = this.Automator.ElementsRegistry.GetRegisteredElement(dataGridKey).ToListBox(); 26 | 27 | CruciatusElement element; 28 | try 29 | { 30 | element = listBox.ScrollTo(strategy); 31 | } 32 | catch (CruciatusException exception) 33 | { 34 | return this.JsonResponse(ResponseStatus.NoSuchElement, exception); 35 | } 36 | 37 | var elementKey = this.Automator.ElementsRegistry.RegisterElement(element); 38 | 39 | return this.JsonResponse(ResponseStatus.Success, new JsonElementContent(elementKey)); 40 | } 41 | 42 | #endregion 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/SelectDataGridCellExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Exceptions; 6 | using Winium.Cruciatus.Extensions; 7 | using Winium.StoreApps.Common; 8 | 9 | #endregion 10 | 11 | internal class SelectDataGridCellExecutor : CommandExecutorBase 12 | { 13 | #region Methods 14 | 15 | protected override string DoImpl() 16 | { 17 | var dataGridKey = this.ExecutedCommand.Parameters["ID"].ToString(); 18 | var column = int.Parse(this.ExecutedCommand.Parameters["COLUMN"].ToString()); 19 | var row = int.Parse(this.ExecutedCommand.Parameters["ROW"].ToString()); 20 | 21 | var dataGrid = this.Automator.ElementsRegistry.GetRegisteredElement(dataGridKey).ToDataGrid(); 22 | 23 | try 24 | { 25 | dataGrid.SelectCell(row, column); 26 | } 27 | catch (CruciatusException exception) 28 | { 29 | return this.JsonResponse(ResponseStatus.NoSuchElement, exception); 30 | } 31 | 32 | return this.JsonResponse(); 33 | } 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/SelectMenuItemExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus.Exceptions; 6 | using Winium.Cruciatus.Extensions; 7 | using Winium.StoreApps.Common; 8 | 9 | #endregion 10 | 11 | internal class SelectMenuItemExecutor : CommandExecutorBase 12 | { 13 | #region Methods 14 | 15 | protected override string DoImpl() 16 | { 17 | var dataGridKey = this.ExecutedCommand.Parameters["ID"].ToString(); 18 | var headersPath = this.ExecutedCommand.Parameters["PATH"].ToString(); 19 | 20 | var menu = this.Automator.ElementsRegistry.GetRegisteredElement(dataGridKey).ToMenu(); 21 | 22 | try 23 | { 24 | menu.SelectItem(headersPath); 25 | } 26 | catch (CruciatusException exception) 27 | { 28 | return this.JsonResponse(ResponseStatus.NoSuchElement, exception); 29 | } 30 | 31 | return this.JsonResponse(); 32 | } 33 | 34 | #endregion 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/SendKeysToActiveElementExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.Linq; 7 | 8 | #endregion 9 | 10 | internal class SendKeysToActiveElementExecutor : CommandExecutorBase 11 | { 12 | #region Methods 13 | 14 | protected override string DoImpl() 15 | { 16 | var chars = this.ExecutedCommand.Parameters["value"].Select(x => Convert.ToChar(x.ToString())); 17 | 18 | this.Automator.WiniumKeyboard.SendKeys(chars.ToArray()); 19 | 20 | return this.JsonResponse(); 21 | } 22 | 23 | #endregion 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/SendKeysToElementExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | internal class SendKeysToElementExecutor : CommandExecutorBase 4 | { 5 | #region Methods 6 | 7 | protected override string DoImpl() 8 | { 9 | var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); 10 | var text = string.Join(string.Empty, this.ExecutedCommand.Parameters["value"]); 11 | 12 | var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); 13 | element.SetText(text); 14 | 15 | return this.JsonResponse(); 16 | } 17 | 18 | #endregion 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/SetOrientationExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System; 6 | 7 | using Winium.StoreApps.Common; 8 | using Winium.Cruciatus.Core; 9 | 10 | #endregion using 11 | 12 | internal class SetOrientationExecutor : CommandExecutorBase 13 | { 14 | #region Methods 15 | 16 | protected override string DoImpl() 17 | { 18 | if (!this.ExecutedCommand.Parameters.ContainsKey("orientation")) 19 | { 20 | // TODO: in the future '400 : invalid argument' will be used 21 | return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); 22 | } 23 | 24 | var orientation = (DisplayOrientation)Enum.Parse( 25 | typeof(DisplayOrientation), 26 | this.ExecutedCommand.Parameters["orientation"].ToString()); 27 | 28 | var result = RotationManager.SetOrientation(orientation); 29 | 30 | string message; 31 | 32 | switch (result) 33 | { 34 | case 0: 35 | return this.JsonResponse(); 36 | case 1: 37 | message = "A device restart is required"; 38 | break; 39 | case -2: 40 | message = this.ExecutedCommand.Parameters["orientation"] + " not supported by device"; 41 | break; 42 | default: 43 | message = "Unknown error: " + result; 44 | break; 45 | } 46 | 47 | Logger.Warn(message); 48 | return this.JsonResponse(ResponseStatus.UnknownError, message); 49 | } 50 | 51 | #endregion 52 | } 53 | } -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/StatusExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Collections.Generic; 6 | 7 | using Winium.Desktop.Driver.CommandHelpers; 8 | using Winium.StoreApps.Common; 9 | 10 | #endregion 11 | 12 | internal class StatusExecutor : CommandExecutorBase 13 | { 14 | #region Methods 15 | 16 | protected override string DoImpl() 17 | { 18 | var response = new Dictionary { { "build", new BuildInfo() }, { "os", new OSInfo() } }; 19 | return this.JsonResponse(ResponseStatus.Success, response); 20 | } 21 | 22 | #endregion 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/SubmitElementExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using Winium.Cruciatus; 6 | 7 | #endregion 8 | 9 | internal class SubmitElementExecutor : CommandExecutorBase 10 | { 11 | #region Methods 12 | 13 | protected override string DoImpl() 14 | { 15 | CruciatusFactory.Keyboard.SendEnter(); 16 | return this.JsonResponse(); 17 | } 18 | 19 | #endregion 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandExecutors/SwitchToWindowExecutor.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandExecutors 2 | { 3 | #region using 4 | 5 | using System.Windows.Automation; 6 | using Winium.Cruciatus; 7 | using Winium.Cruciatus.Core; 8 | using Winium.StoreApps.Common; 9 | using Winium.StoreApps.Common.Exceptions; 10 | 11 | #endregion 12 | 13 | internal class SwitchToWindowExecutor : CommandExecutorBase 14 | { 15 | #region Methods 16 | 17 | protected override string DoImpl() 18 | { 19 | var windowHandle = int.Parse(this.ExecutedCommand.Parameters["name"].ToString()); 20 | 21 | var handleProperty = AutomationElement.NativeWindowHandleProperty; 22 | var window = CruciatusFactory.Root.FindElement(By.AutomationProperty(handleProperty, windowHandle)); 23 | if (window == null) 24 | { 25 | throw new AutomationException("Window cannot be found", ResponseStatus.NoSuchElement); 26 | } 27 | 28 | window.SetFocus(); 29 | 30 | return this.JsonResponse(); 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandHelpers/BuildInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandHelpers 2 | { 3 | #region using 4 | 5 | using System.Reflection; 6 | 7 | using Newtonsoft.Json; 8 | 9 | #endregion 10 | 11 | public class BuildInfo 12 | { 13 | #region Static Fields 14 | 15 | private static string version; 16 | 17 | #endregion 18 | 19 | #region Public Properties 20 | 21 | [JsonProperty("version")] 22 | public string Version 23 | { 24 | get 25 | { 26 | return version ?? (version = Assembly.GetExecutingAssembly().GetName().Version.ToString()); 27 | } 28 | } 29 | 30 | #endregion 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandHelpers/OSInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.CommandHelpers 2 | { 3 | #region using 4 | 5 | using System; 6 | 7 | using Newtonsoft.Json; 8 | 9 | #endregion 10 | 11 | // ReSharper disable once InconsistentNaming 12 | public class OSInfo 13 | { 14 | #region Static Fields 15 | 16 | private static string architecture; 17 | 18 | private static string version; 19 | 20 | #endregion 21 | 22 | #region Public Properties 23 | 24 | [JsonProperty("arch")] 25 | public string Architecture 26 | { 27 | get 28 | { 29 | return architecture ?? (architecture = Environment.Is64BitOperatingSystem ? "x64" : "x86"); 30 | } 31 | } 32 | 33 | [JsonProperty("name")] 34 | public string Name 35 | { 36 | get 37 | { 38 | return "windows"; 39 | } 40 | } 41 | 42 | [JsonProperty("version")] 43 | public string Version 44 | { 45 | get 46 | { 47 | return version ?? (version = Environment.OSVersion.VersionString); 48 | } 49 | } 50 | 51 | #endregion 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/CommandLineOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver 2 | { 3 | #region using 4 | 5 | using CommandLine; 6 | using CommandLine.Text; 7 | 8 | #endregion 9 | 10 | internal class CommandLineOptions 11 | { 12 | #region Public Properties 13 | 14 | [Option("log-path", Required = false, 15 | HelpText = "write server log to file instead of stdout, increases log level to INFO")] 16 | public string LogPath { get; set; } 17 | 18 | [Option("port", Required = false, HelpText = "port to listen on")] 19 | public int? Port { get; set; } 20 | 21 | [Option("url-base", Required = false, HelpText = "base URL path prefix for commands, e.g. wd/url")] 22 | public string UrlBase { get; set; } 23 | 24 | [Option("verbose", Required = false, HelpText = "log verbosely")] 25 | public bool Verbose { get; set; } 26 | 27 | [Option("silent", Required = false, HelpText = "log nothing")] 28 | public bool Silent { get; set; } 29 | 30 | #endregion 31 | 32 | #region Public Methods and Operators 33 | 34 | [HelpOption] 35 | public string GetUsage() 36 | { 37 | return HelpText.AutoBuild(this, current => HelpText.DefaultParsingErrorsHandler(this, current)); 38 | } 39 | 40 | #endregion 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/ElementsRegistry.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver 2 | { 3 | #region using 4 | 5 | using System.Collections.Generic; 6 | using System.Globalization; 7 | using System.Linq; 8 | using System.Threading; 9 | 10 | using Winium.Cruciatus.Elements; 11 | using Winium.StoreApps.Common; 12 | using Winium.StoreApps.Common.Exceptions; 13 | 14 | #endregion 15 | 16 | internal class ElementsRegistry 17 | { 18 | #region Static Fields 19 | 20 | private static int safeInstanceCount; 21 | 22 | #endregion 23 | 24 | #region Fields 25 | 26 | private readonly Dictionary registeredElements; 27 | 28 | #endregion 29 | 30 | #region Constructors and Destructors 31 | 32 | public ElementsRegistry() 33 | { 34 | this.registeredElements = new Dictionary(); 35 | } 36 | 37 | #endregion 38 | 39 | #region Public Methods and Operators 40 | 41 | public void Clear() 42 | { 43 | this.registeredElements.Clear(); 44 | } 45 | 46 | /// 47 | /// Returns CruciatusElement registered with specified key if any exists. Throws if no element is found. 48 | /// 49 | /// 50 | /// Registered element is not found or element has been garbage collected. 51 | /// 52 | public CruciatusElement GetRegisteredElement(string registeredKey) 53 | { 54 | var element = this.GetRegisteredElementOrNull(registeredKey); 55 | if (element != null) 56 | { 57 | return element; 58 | } 59 | 60 | throw new AutomationException("Stale element reference", ResponseStatus.StaleElementReference); 61 | } 62 | 63 | public string RegisterElement(CruciatusElement element) 64 | { 65 | var registeredKey = 66 | this.registeredElements.FirstOrDefault( 67 | x => x.Value.Properties.RuntimeId == element.Properties.RuntimeId).Key; 68 | 69 | if (registeredKey == null) 70 | { 71 | Interlocked.Increment(ref safeInstanceCount); 72 | 73 | // TODO: Maybe use RuntimeId how registeredKey? 74 | registeredKey = element.GetHashCode() + "-" 75 | + safeInstanceCount.ToString(string.Empty, CultureInfo.InvariantCulture); 76 | this.registeredElements.Add(registeredKey, element); 77 | } 78 | 79 | return registeredKey; 80 | } 81 | 82 | public IEnumerable RegisterElements(IEnumerable elements) 83 | { 84 | return elements.Select(this.RegisterElement); 85 | } 86 | 87 | #endregion 88 | 89 | #region Methods 90 | 91 | internal CruciatusElement GetRegisteredElementOrNull(string registeredKey) 92 | { 93 | CruciatusElement element; 94 | this.registeredElements.TryGetValue(registeredKey, out element); 95 | return element; 96 | } 97 | 98 | #endregion 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Extensions/AutomationPropertyHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.Extensions 2 | { 3 | #region using 4 | 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Windows.Automation; 9 | 10 | using Winium.Cruciatus; 11 | using Winium.Cruciatus.Exceptions; 12 | 13 | #endregion 14 | 15 | internal static class AutomationPropertyHelper 16 | { 17 | #region Static Fields 18 | 19 | private static readonly Dictionary Properties; 20 | 21 | #endregion 22 | 23 | #region Constructors and Destructors 24 | 25 | static AutomationPropertyHelper() 26 | { 27 | Properties = 28 | typeof(AutomationElementIdentifiers).GetFields(BindingFlags.Public | BindingFlags.Static) 29 | .Where(f => f.FieldType == typeof(AutomationProperty)) 30 | .ToDictionary(f => f.Name, f => (AutomationProperty)f.GetValue(null)); 31 | } 32 | 33 | #endregion 34 | 35 | #region Public Methods and Operators 36 | 37 | internal static AutomationProperty GetAutomationProperty(string propertyName) 38 | { 39 | const string Suffix = "Property"; 40 | var fullPropertyName = propertyName.EndsWith(Suffix) ? propertyName : propertyName + Suffix; 41 | if (Properties.ContainsKey(fullPropertyName)) 42 | { 43 | return Properties[fullPropertyName]; 44 | } 45 | 46 | CruciatusFactory.Logger.Error(string.Format("Property '{0}' is not UI Automation Property", propertyName)); 47 | throw new CruciatusException("UNSUPPORTED PROPERTY"); 48 | } 49 | 50 | #endregion 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Extensions/ByHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.Extensions 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.Windows.Automation; 7 | 8 | using Winium.Cruciatus.Core; 9 | 10 | #endregion 11 | 12 | public static class ByHelper 13 | { 14 | #region Public Methods and Operators 15 | 16 | public static By GetStrategy(string strategy, string value) 17 | { 18 | switch (strategy) 19 | { 20 | case "id": 21 | return By.Uid(value); 22 | case "name": 23 | return By.Name(value); 24 | case "class name": 25 | return By.AutomationProperty(AutomationElementIdentifiers.ClassNameProperty, value); 26 | case "xpath": 27 | return By.XPath(value); 28 | default: 29 | throw new NotImplementedException( 30 | string.Format("'{0}' is not valid or implemented searching strategy.", strategy)); 31 | } 32 | } 33 | 34 | #endregion 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/HttpRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Globalization; 8 | using System.IO; 9 | using System.Linq; 10 | 11 | #endregion 12 | 13 | public class HttpRequest 14 | { 15 | #region Public Properties 16 | 17 | public Dictionary Headers { get; set; } 18 | 19 | public string MessageBody { get; private set; } 20 | 21 | public string StartingLine { get; private set; } 22 | 23 | #endregion 24 | 25 | #region Public Methods and Operators 26 | 27 | public static HttpRequest ReadFromStreamWithoutClosing(Stream stream) 28 | { 29 | var request = new HttpRequest(); 30 | var streamReader = new StreamReader(stream); 31 | 32 | request.StartingLine = streamReader.ReadLine(); 33 | 34 | request.Headers = ReadHeaders(streamReader); 35 | 36 | var contentLength = GetContentLength(request.Headers); 37 | request.MessageBody = contentLength != 0 ? ReadContent(streamReader, contentLength) : string.Empty; 38 | 39 | return request; 40 | } 41 | 42 | #endregion 43 | 44 | #region Methods 45 | 46 | private static int GetContentLength(IReadOnlyDictionary headers) 47 | { 48 | var contentLength = 0; 49 | string contentLengthString; 50 | if (headers.TryGetValue("Content-Length", out contentLengthString)) 51 | { 52 | contentLength = Convert.ToInt32(contentLengthString, CultureInfo.InvariantCulture); 53 | } 54 | 55 | return contentLength; 56 | } 57 | 58 | // reads the content of a request depending on its length 59 | private static string ReadContent(TextReader textReader, int contentLength) 60 | { 61 | var readBuffer = new char[contentLength]; 62 | textReader.Read(readBuffer, 0, readBuffer.Length); 63 | return readBuffer.Aggregate(string.Empty, (current, ch) => current + ch); 64 | } 65 | 66 | private static Dictionary ReadHeaders(TextReader textReader) 67 | { 68 | var headers = new Dictionary(); 69 | string header; 70 | while (!string.IsNullOrEmpty(header = textReader.ReadLine())) 71 | { 72 | var splitHeader = header.Split(':'); 73 | headers.Add(splitHeader[0], splitHeader[1].Trim(' ')); 74 | } 75 | 76 | return headers; 77 | } 78 | 79 | #endregion 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Input/KeyEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.Input 2 | { 3 | #region using 4 | 5 | using OpenQA.Selenium; 6 | 7 | #endregion 8 | 9 | internal class KeyEvent 10 | { 11 | #region Fields 12 | 13 | private readonly char character; 14 | 15 | private readonly string unicodeKey; 16 | 17 | #endregion 18 | 19 | #region Constructors and Destructors 20 | 21 | public KeyEvent(char ch) 22 | { 23 | this.character = ch; 24 | this.unicodeKey = KeyboardModifiers.GetKeyFromUnicode(this.character); 25 | } 26 | 27 | #endregion 28 | 29 | #region Public Methods and Operators 30 | 31 | public char GetCharacter() 32 | { 33 | return this.character; 34 | } 35 | 36 | public string GetKey() 37 | { 38 | return this.unicodeKey; 39 | } 40 | 41 | public bool IsModifier() 42 | { 43 | return KeyboardModifiers.IsModifier(this.unicodeKey); 44 | } 45 | 46 | public bool IsModifierRelease() 47 | { 48 | return this.GetKey() == Keys.Null; 49 | } 50 | 51 | public bool IsNewLine() 52 | { 53 | return this.GetCharacter() == '\n'; 54 | } 55 | 56 | #endregion 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Input/KeyboardModifiers.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.Input 2 | { 3 | #region using 4 | 5 | using System.Collections.Generic; 6 | 7 | using OpenQA.Selenium; 8 | 9 | using WindowsInput.Native; 10 | 11 | #endregion 12 | 13 | internal class KeyboardModifiers : List 14 | { 15 | #region Static Fields 16 | 17 | private static readonly List Modifiers = new List 18 | { 19 | Keys.Control, 20 | Keys.LeftControl, 21 | Keys.Shift, 22 | Keys.LeftShift, 23 | Keys.Alt, 24 | Keys.LeftAlt 25 | }; 26 | 27 | private static readonly Dictionary ModifiersMap = 28 | new Dictionary 29 | { 30 | { Keys.Control, VirtualKeyCode.CONTROL }, 31 | { Keys.Shift, VirtualKeyCode.SHIFT }, 32 | { Keys.Alt, VirtualKeyCode.MENU }, 33 | }; 34 | 35 | #endregion 36 | 37 | #region Public Methods and Operators 38 | 39 | public static string GetKeyFromUnicode(char key) 40 | { 41 | return Modifiers.Find(modifier => modifier[0] == key); 42 | } 43 | 44 | public static VirtualKeyCode GetVirtualKeyCode(string key) 45 | { 46 | VirtualKeyCode virtualKey; 47 | 48 | if (ModifiersMap.TryGetValue(key, out virtualKey)) 49 | { 50 | return virtualKey; 51 | } 52 | 53 | return default(VirtualKeyCode); 54 | } 55 | 56 | public static bool IsModifier(string key) 57 | { 58 | return Modifiers.Contains(key); 59 | } 60 | 61 | #endregion 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Input/WiniumKeyboard.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver.Input 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | using OpenQA.Selenium; 10 | 11 | using Winium.Cruciatus; 12 | using Winium.Cruciatus.Settings; 13 | 14 | #endregion 15 | 16 | internal class WiniumKeyboard 17 | { 18 | #region Fields 19 | 20 | private readonly KeyboardModifiers modifiers = new KeyboardModifiers(); 21 | 22 | #endregion 23 | 24 | #region Constructors and Destructors 25 | 26 | public WiniumKeyboard(KeyboardSimulatorType keyboardSimulatorType) 27 | { 28 | CruciatusFactory.Settings.KeyboardSimulatorType = keyboardSimulatorType; 29 | } 30 | 31 | #endregion 32 | 33 | #region Public Methods and Operators 34 | 35 | public void KeyDown(string keyToPress) 36 | { 37 | var key = KeyboardModifiers.GetVirtualKeyCode(keyToPress); 38 | this.modifiers.Add(keyToPress); 39 | CruciatusFactory.Keyboard.KeyDown(key); 40 | } 41 | 42 | public void KeyUp(string keyToRelease) 43 | { 44 | var key = KeyboardModifiers.GetVirtualKeyCode(keyToRelease); 45 | this.modifiers.Remove(keyToRelease); 46 | CruciatusFactory.Keyboard.KeyUp(key); 47 | } 48 | 49 | public void SendKeys(char[] keysToSend) 50 | { 51 | var builder = keysToSend.Select(key => new KeyEvent(key)).ToList(); 52 | 53 | this.SendKeys(builder); 54 | } 55 | 56 | #endregion 57 | 58 | #region Methods 59 | 60 | protected void ReleaseModifiers() 61 | { 62 | var tmp = this.modifiers.ToList(); 63 | 64 | foreach (var modifierKey in tmp) 65 | { 66 | this.KeyUp(modifierKey); 67 | } 68 | } 69 | 70 | private void PressOrReleaseModifier(string modifier) 71 | { 72 | if (this.modifiers.Contains(modifier)) 73 | { 74 | this.KeyUp(modifier); 75 | } 76 | else 77 | { 78 | this.KeyDown(modifier); 79 | } 80 | } 81 | 82 | private void SendKeys(IEnumerable events) 83 | { 84 | foreach (var keyEvent in events) 85 | { 86 | if (keyEvent.IsNewLine()) 87 | { 88 | CruciatusFactory.Keyboard.SendEnter(); 89 | } 90 | else if (keyEvent.IsModifierRelease()) 91 | { 92 | this.ReleaseModifiers(); 93 | } 94 | else if (keyEvent.IsModifier()) 95 | { 96 | this.PressOrReleaseModifier(keyEvent.GetKey()); 97 | } 98 | else 99 | { 100 | this.Type(keyEvent.GetCharacter()); 101 | } 102 | } 103 | } 104 | 105 | private void Type(char key) 106 | { 107 | string str = Convert.ToString(key); 108 | 109 | if (this.modifiers.Contains(Keys.LeftShift) || this.modifiers.Contains(Keys.Shift)) 110 | { 111 | str = str.ToUpper(); 112 | } 113 | 114 | CruciatusFactory.Keyboard.SendText(str); 115 | } 116 | 117 | #endregion 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Listener.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.Globalization; 7 | using System.IO; 8 | using System.Net; 9 | using System.Net.Sockets; 10 | 11 | using Winium.StoreApps.Common; 12 | 13 | #endregion 14 | 15 | public class Listener 16 | { 17 | #region Static Fields 18 | 19 | private static string urnPrefix; 20 | 21 | #endregion 22 | 23 | #region Fields 24 | 25 | private UriDispatchTables dispatcher; 26 | 27 | private CommandExecutorDispatchTable executorDispatcher; 28 | 29 | private TcpListener listener; 30 | 31 | #endregion 32 | 33 | #region Constructors and Destructors 34 | 35 | public Listener(int listenerPort) 36 | { 37 | this.Port = listenerPort; 38 | } 39 | 40 | #endregion 41 | 42 | #region Public Properties 43 | 44 | public static string UrnPrefix 45 | { 46 | get 47 | { 48 | return urnPrefix; 49 | } 50 | 51 | set 52 | { 53 | if (!string.IsNullOrEmpty(value)) 54 | { 55 | // Normalize prefix 56 | urnPrefix = "/" + value.Trim('/'); 57 | } 58 | } 59 | } 60 | 61 | public int Port { get; private set; } 62 | 63 | public Uri Prefix { get; private set; } 64 | 65 | #endregion 66 | 67 | #region Public Methods and Operators 68 | 69 | public void StartListening() 70 | { 71 | try 72 | { 73 | this.listener = new TcpListener(IPAddress.Any, this.Port); 74 | 75 | this.Prefix = new Uri(string.Format(CultureInfo.InvariantCulture, "http://localhost:{0}", this.Port)); 76 | this.dispatcher = new UriDispatchTables(new Uri(this.Prefix, UrnPrefix)); 77 | this.executorDispatcher = new CommandExecutorDispatchTable(); 78 | 79 | // Start listening for client requests. 80 | this.listener.Start(); 81 | 82 | // Enter the listening loop 83 | while (true) 84 | { 85 | Logger.Debug("Waiting for a connection..."); 86 | 87 | // Perform a blocking call to accept requests. 88 | var client = this.listener.AcceptTcpClient(); 89 | 90 | // Get a stream object for reading and writing 91 | using (var stream = client.GetStream()) 92 | { 93 | var acceptedRequest = HttpRequest.ReadFromStreamWithoutClosing(stream); 94 | 95 | if (string.IsNullOrWhiteSpace(acceptedRequest.StartingLine)) 96 | { 97 | Logger.Warn("ACCEPTED EMPTY REQUEST"); 98 | } 99 | else 100 | { 101 | Logger.Debug("ACCEPTED REQUEST {0}", acceptedRequest.StartingLine); 102 | 103 | var response = this.HandleRequest(acceptedRequest); 104 | using (var writer = new StreamWriter(stream)) 105 | { 106 | try 107 | { 108 | writer.Write(response); 109 | writer.Flush(); 110 | } 111 | catch (IOException ex) 112 | { 113 | Logger.Error("Error occured while writing response: {0}", ex); 114 | } 115 | } 116 | } 117 | 118 | // Shutdown and end connection 119 | } 120 | 121 | client.Close(); 122 | 123 | Logger.Debug("Client closed\n"); 124 | } 125 | } 126 | catch (SocketException ex) 127 | { 128 | Logger.Error("SocketException occurred while trying to start listner: {0}", ex); 129 | throw; 130 | } 131 | catch (ArgumentException ex) 132 | { 133 | Logger.Error("ArgumentException occurred while trying to start listner: {0}", ex); 134 | throw; 135 | } 136 | finally 137 | { 138 | // Stop listening for new clients. 139 | this.listener.Stop(); 140 | } 141 | } 142 | 143 | public void StopListening() 144 | { 145 | this.listener.Stop(); 146 | } 147 | 148 | #endregion 149 | 150 | #region Methods 151 | 152 | private string HandleRequest(HttpRequest acceptedRequest) 153 | { 154 | var firstHeaderTokens = acceptedRequest.StartingLine.Split(' '); 155 | var method = firstHeaderTokens[0]; 156 | var resourcePath = firstHeaderTokens[1]; 157 | 158 | var uriToMatch = new Uri(this.Prefix, resourcePath); 159 | var matched = this.dispatcher.Match(method, uriToMatch); 160 | 161 | if (matched == null) 162 | { 163 | Logger.Warn("Unknown command recived: {0}", uriToMatch); 164 | return HttpResponseHelper.ResponseString(HttpStatusCode.NotFound, "Unknown command " + uriToMatch); 165 | } 166 | 167 | var commandName = matched.Data.ToString(); 168 | var commandToExecute = new Command(commandName, acceptedRequest.MessageBody); 169 | foreach (string variableName in matched.BoundVariables.Keys) 170 | { 171 | commandToExecute.Parameters[variableName] = matched.BoundVariables[variableName]; 172 | } 173 | 174 | var commandResponse = this.ProcessCommand(commandToExecute); 175 | return HttpResponseHelper.ResponseString(commandResponse.HttpStatusCode, commandResponse.Content); 176 | } 177 | 178 | private CommandResponse ProcessCommand(Command command) 179 | { 180 | Logger.Info("COMMAND {0}\r\n{1}", command.Name, command.Parameters.ToString()); 181 | var executor = this.executorDispatcher.GetExecutor(command.Name); 182 | executor.ExecutedCommand = command; 183 | var respnose = executor.Do(); 184 | Logger.Debug("RESPONSE:\r\n{0}", respnose); 185 | 186 | return respnose; 187 | } 188 | 189 | #endregion 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Logger.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver 2 | { 3 | #region using 4 | 5 | using System.ComponentModel; 6 | 7 | using NLog; 8 | using NLog.Targets; 9 | 10 | #endregion 11 | 12 | internal static class Logger 13 | { 14 | #region Constants 15 | 16 | private const string LayoutFormat = "${date:format=HH\\:mm\\:ss} [${level:uppercase=true}] ${message}"; 17 | 18 | #endregion 19 | 20 | #region Static Fields 21 | 22 | private static readonly NLog.Logger Log = LogManager.GetLogger("outerdriver"); 23 | 24 | #endregion 25 | 26 | #region Public Methods and Operators 27 | 28 | public static void Debug([Localizable(false)] string message, params object[] args) 29 | { 30 | Log.Debug(message, args); 31 | } 32 | 33 | public static void Error([Localizable(false)] string message, params object[] args) 34 | { 35 | Log.Error(message, args); 36 | } 37 | 38 | public static void Fatal([Localizable(false)] string message, params object[] args) 39 | { 40 | Log.Fatal(message, args); 41 | } 42 | 43 | public static void Info([Localizable(false)] string message, params object[] args) 44 | { 45 | Log.Info(message, args); 46 | } 47 | 48 | public static void TargetConsole(bool verbose) 49 | { 50 | var target = new ConsoleTarget { Layout = LayoutFormat }; 51 | 52 | NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(target, verbose ? LogLevel.Debug : LogLevel.Fatal); 53 | LogManager.ReconfigExistingLoggers(); 54 | } 55 | 56 | public static void TargetFile(string fileName, bool verbose) 57 | { 58 | var target = new FileTarget { Layout = LayoutFormat, FileName = fileName }; 59 | 60 | NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(target, verbose ? LogLevel.Debug : LogLevel.Info); 61 | LogManager.ReconfigExistingLoggers(); 62 | } 63 | 64 | public static void TargetNull() 65 | { 66 | NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(new NullTarget()); 67 | LogManager.ReconfigExistingLoggers(); 68 | } 69 | 70 | public static void Trace([Localizable(false)] string message, params object[] args) 71 | { 72 | Log.Trace(message, args); 73 | } 74 | 75 | public static void Warn([Localizable(false)] string message, params object[] args) 76 | { 77 | Log.Warn(message, args); 78 | } 79 | 80 | #endregion 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver 2 | { 3 | #region using 4 | 5 | using System; 6 | 7 | #endregion 8 | 9 | internal class Program 10 | { 11 | #region Methods 12 | 13 | [STAThread] 14 | private static void Main(string[] args) 15 | { 16 | var listeningPort = 9999; 17 | 18 | var options = new CommandLineOptions(); 19 | if (CommandLine.Parser.Default.ParseArguments(args, options)) 20 | { 21 | if (options.Port.HasValue) 22 | { 23 | listeningPort = options.Port.Value; 24 | } 25 | } 26 | 27 | if (options.LogPath != null) 28 | { 29 | Logger.TargetFile(options.LogPath, options.Verbose); 30 | } 31 | else if (!options.Silent) 32 | { 33 | Logger.TargetConsole(options.Verbose); 34 | } 35 | else 36 | { 37 | Logger.TargetNull(); 38 | } 39 | 40 | try 41 | { 42 | var listener = new Listener(listeningPort); 43 | Listener.UrnPrefix = options.UrlBase; 44 | 45 | Console.WriteLine("Starting Windows Desktop Driver on port {0}\n", listeningPort); 46 | 47 | listener.StartListening(); 48 | } 49 | catch (Exception ex) 50 | { 51 | Logger.Fatal("Failed to start driver: {0}", ex); 52 | throw; 53 | } 54 | } 55 | 56 | #endregion 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region using 2 | 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | 6 | #endregion 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | [assembly: AssemblyTitle("Winium.Desktop.Driver")] 12 | [assembly: AssemblyDescription("Selenium Remote WebDriver implementation for test automation of Windows application based on WinFroms and WPF platforms.")] 13 | [assembly: AssemblyConfiguration("")] 14 | [assembly: AssemblyCompany("")] 15 | [assembly: AssemblyProduct("Winium.Desktop.Driver")] 16 | [assembly: AssemblyCopyright("Copyright © 2015")] 17 | [assembly: AssemblyTrademark("")] 18 | [assembly: AssemblyCulture("")] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | [assembly: ComVisible(false)] 24 | 25 | // The following GUID is for the ID of the typelib if this project is exposed to COM 26 | [assembly: Guid("2878a69b-16cd-455a-8f46-6323e9109635")] 27 | 28 | // Version information for an assembly consists of the following four values: 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.2.0.0")] 37 | [assembly: AssemblyFileVersion("1.6.0.*")] 38 | [assembly: AssemblyInformationalVersion("1.6.0")] 39 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/Requester.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.Desktop.Driver 2 | { 3 | #region using 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Globalization; 8 | using System.IO; 9 | using System.Net; 10 | 11 | using Newtonsoft.Json; 12 | 13 | using Winium.StoreApps.Common; 14 | using Winium.StoreApps.Common.Exceptions; 15 | 16 | #endregion 17 | 18 | internal class Requester 19 | { 20 | #region Fields 21 | 22 | private readonly string ip; 23 | 24 | private readonly int port; 25 | 26 | #endregion 27 | 28 | #region Constructors and Destructors 29 | 30 | public Requester(string ip, int port) 31 | { 32 | this.ip = ip; 33 | this.port = port; 34 | } 35 | 36 | #endregion 37 | 38 | #region Public Methods and Operators 39 | 40 | public string ForwardCommand(Command commandToForward, bool verbose = true, int timeout = 0) 41 | { 42 | var serializedCommand = JsonConvert.SerializeObject(commandToForward); 43 | 44 | var response = this.SendRequest(serializedCommand, verbose, timeout); 45 | if (response.Key == HttpStatusCode.OK) 46 | { 47 | return response.Value; 48 | } 49 | 50 | throw new InnerDriverRequestException(response.Value, response.Key); 51 | } 52 | 53 | public KeyValuePair SendRequest(string requestContent, bool verbose, int timeout) 54 | { 55 | var result = string.Empty; 56 | StreamReader reader = null; 57 | HttpWebResponse response = null; 58 | var status = HttpStatusCode.OK; 59 | try 60 | { 61 | // create the request 62 | var uri = string.Format(CultureInfo.InvariantCulture, "http://{0}:{1}", this.ip, this.port); 63 | var request = CreateWebRequest(uri, requestContent); 64 | if (timeout != 0) 65 | { 66 | request.Timeout = timeout; 67 | } 68 | 69 | if (verbose) 70 | { 71 | Logger.Debug("Sending request to inner driver: {0}", uri); 72 | } 73 | 74 | // send the request and get the response 75 | try 76 | { 77 | response = request.GetResponse() as HttpWebResponse; 78 | } 79 | catch (WebException ex) 80 | { 81 | response = ex.Response as HttpWebResponse; 82 | } 83 | 84 | if (response != null) 85 | { 86 | status = response.StatusCode; 87 | var stream = response.GetResponseStream(); 88 | if (stream == null) 89 | { 90 | throw new NullReferenceException("No response stream."); 91 | } 92 | 93 | // read and return the response 94 | reader = new StreamReader(stream); 95 | result = reader.ReadToEnd(); 96 | } 97 | } 98 | catch (Exception ex) 99 | { 100 | if (verbose) 101 | { 102 | // No need to log exceptions raised when sending service commands like ping. 103 | Logger.Error("Error occurred while trying to send request to inner driver: {0}", ex); 104 | } 105 | } 106 | finally 107 | { 108 | if (response != null) 109 | { 110 | response.Close(); 111 | } 112 | 113 | if (reader != null) 114 | { 115 | reader.Close(); 116 | } 117 | } 118 | 119 | return new KeyValuePair(status, result); 120 | } 121 | 122 | #endregion 123 | 124 | #region Methods 125 | 126 | private static HttpWebRequest CreateWebRequest(string uri, string content) 127 | { 128 | // create request 129 | var request = (HttpWebRequest)WebRequest.Create(uri); 130 | request.ContentType = "application/json"; 131 | request.Method = "POST"; 132 | request.KeepAlive = false; 133 | 134 | // write request body 135 | if (!string.IsNullOrEmpty(content)) 136 | { 137 | var writer = new StreamWriter(request.GetRequestStream()); 138 | writer.Write(content); 139 | writer.Close(); 140 | } 141 | 142 | return request; 143 | } 144 | 145 | #endregion 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/Winium.Desktop.Driver/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/Command.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.StoreApps.Common 2 | { 3 | #region 4 | 5 | using System.Collections.Generic; 6 | 7 | using Newtonsoft.Json; 8 | using Newtonsoft.Json.Linq; 9 | 10 | #endregion 11 | 12 | public class Command 13 | { 14 | #region Fields 15 | 16 | private IDictionary commandParameters = new JObject(); 17 | 18 | #endregion 19 | 20 | #region Constructors and Destructors 21 | 22 | public Command(string name, IDictionary parameters) 23 | { 24 | this.Name = name; 25 | if (parameters != null) 26 | { 27 | this.Parameters = parameters; 28 | } 29 | } 30 | 31 | public Command(string name, string jsonParameters) 32 | : this(name, string.IsNullOrEmpty(jsonParameters) ? null : JObject.Parse(jsonParameters)) 33 | { 34 | } 35 | 36 | public Command(string name) 37 | { 38 | this.Name = name; 39 | } 40 | 41 | public Command() 42 | { 43 | } 44 | 45 | #endregion 46 | 47 | #region Public Properties 48 | 49 | /// 50 | /// Gets the command name 51 | /// 52 | [JsonProperty("name")] 53 | public string Name { get; set; } 54 | 55 | /// 56 | /// Gets the parameters of the command 57 | /// 58 | [JsonProperty("parameters")] 59 | public IDictionary Parameters 60 | { 61 | get 62 | { 63 | return this.commandParameters; 64 | } 65 | 66 | set 67 | { 68 | this.commandParameters = value; 69 | } 70 | } 71 | 72 | /// 73 | /// Gets the SessionID of the command 74 | /// 75 | [JsonProperty("sessionId")] 76 | public string SessionId { get; set; } 77 | 78 | #endregion 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/CommandInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.StoreApps.Common 2 | { 3 | public class CommandInfo 4 | { 5 | #region Constants 6 | 7 | public const string DeleteCommand = "DELETE"; 8 | 9 | public const string GetCommand = "GET"; 10 | 11 | public const string PostCommand = "POST"; 12 | 13 | #endregion 14 | 15 | #region Constructors and Destructors 16 | 17 | public CommandInfo(string method, string resourcePath) 18 | { 19 | this.ResourcePath = resourcePath; 20 | this.Method = method; 21 | } 22 | 23 | #endregion 24 | 25 | #region Public Properties 26 | 27 | public string Method { get; set; } 28 | 29 | public string ResourcePath { get; set; } 30 | 31 | #endregion 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/CommandResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.StoreApps.Common 2 | { 3 | #region 4 | 5 | using System.Net; 6 | 7 | #endregion 8 | 9 | public class CommandResponse 10 | { 11 | #region Public Properties 12 | 13 | public string Content { get; set; } 14 | 15 | public HttpStatusCode HttpStatusCode { get; set; } 16 | 17 | #endregion 18 | 19 | #region Public Methods and Operators 20 | 21 | public static CommandResponse Create(HttpStatusCode code, string content) 22 | { 23 | return new CommandResponse { HttpStatusCode = code, Content = content }; 24 | } 25 | 26 | public override string ToString() 27 | { 28 | return string.Format("{0}: {1}", this.HttpStatusCode, this.Content); 29 | } 30 | 31 | #endregion 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/Exceptions/AutomationException.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.StoreApps.Common.Exceptions 2 | { 3 | #region 4 | 5 | using System; 6 | 7 | #endregion 8 | 9 | public class AutomationException : Exception 10 | { 11 | #region Fields 12 | 13 | private ResponseStatus responseStatus = ResponseStatus.UnknownError; 14 | 15 | #endregion 16 | 17 | #region Constructors and Destructors 18 | 19 | public AutomationException() 20 | { 21 | } 22 | 23 | public AutomationException(string message, ResponseStatus status) 24 | : base(message) 25 | { 26 | this.Status = status; 27 | } 28 | 29 | public AutomationException(string message, params object[] args) 30 | : base(string.Format(message, args)) 31 | { 32 | } 33 | 34 | public AutomationException(string message, Exception innerException) 35 | : base(message, innerException) 36 | { 37 | } 38 | 39 | #endregion 40 | 41 | #region Public Properties 42 | 43 | public ResponseStatus Status 44 | { 45 | get 46 | { 47 | return this.responseStatus; 48 | } 49 | 50 | set 51 | { 52 | this.responseStatus = value; 53 | } 54 | } 55 | 56 | #endregion 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/Exceptions/InnerDriverRequestException.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.StoreApps.Common.Exceptions 2 | { 3 | #region 4 | 5 | using System; 6 | using System.Net; 7 | 8 | #endregion 9 | 10 | public class InnerDriverRequestException : Exception 11 | { 12 | #region Constructors and Destructors 13 | 14 | public InnerDriverRequestException() 15 | { 16 | } 17 | 18 | public InnerDriverRequestException(string message, HttpStatusCode statusCode) 19 | : base(message) 20 | { 21 | this.StatusCode = statusCode; 22 | } 23 | 24 | public InnerDriverRequestException(string message, params object[] args) 25 | : base(string.Format(message, args)) 26 | { 27 | } 28 | 29 | public InnerDriverRequestException(string message, Exception innerException) 30 | : base(message, innerException) 31 | { 32 | } 33 | 34 | #endregion 35 | 36 | #region Public Properties 37 | 38 | public HttpStatusCode StatusCode { get; set; } 39 | 40 | #endregion 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/HttpResponseHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.StoreApps.Common 2 | { 3 | #region 4 | 5 | using System.Collections.Generic; 6 | using System.Net; 7 | using System.Text; 8 | 9 | #endregion 10 | 11 | public static class HttpResponseHelper 12 | { 13 | #region Constants 14 | 15 | private const string JsonContentType = "application/json;charset=UTF-8"; 16 | 17 | private const string PlainTextContentType = "text/plain"; 18 | 19 | #endregion 20 | 21 | #region Static Fields 22 | 23 | private static Dictionary statusCodeDescriptors; 24 | 25 | #endregion 26 | 27 | #region Public Properties 28 | 29 | public static Dictionary StatusCodeDescriptors 30 | { 31 | get 32 | { 33 | return statusCodeDescriptors 34 | ?? (statusCodeDescriptors = 35 | new Dictionary 36 | { 37 | { HttpStatusCode.OK, "OK" }, 38 | { HttpStatusCode.BadRequest, "Bad Request" }, 39 | { HttpStatusCode.NotFound, "Not Found" }, 40 | { HttpStatusCode.NotImplemented, "Not Implemented" } 41 | }); 42 | } 43 | } 44 | 45 | #endregion 46 | 47 | #region Public Methods and Operators 48 | 49 | public static bool IsClientError(int code) 50 | { 51 | return code >= 400 && code < 500; 52 | } 53 | 54 | public static string ResponseString(HttpStatusCode statusCode, string content) 55 | { 56 | var contentType = IsClientError((int)statusCode) ? PlainTextContentType : JsonContentType; 57 | 58 | string statusDescription; 59 | StatusCodeDescriptors.TryGetValue(statusCode, out statusDescription); 60 | 61 | var responseString = new StringBuilder(); 62 | responseString.AppendLine(string.Format("HTTP/1.1 {0} {1}", (int)statusCode, statusDescription)); 63 | responseString.AppendLine(string.Format("Content-Type: {0}", contentType)); 64 | responseString.AppendLine("Connection: close"); 65 | responseString.AppendLine(string.Empty); 66 | responseString.AppendLine(content); 67 | 68 | return responseString.ToString(); 69 | } 70 | 71 | #endregion 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/JsonErrorCodes.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.StoreApps.Common 2 | { 3 | #region using 4 | 5 | using System.Collections.Generic; 6 | 7 | #endregion 8 | 9 | public static class JsonErrorCodes 10 | { 11 | // TODO: in the future ResponseStatus will be removed in favor of HTTPStatus (see https://w3c.github.io/webdriver/webdriver-spec.html#handling-errors) 12 | #region Static Fields 13 | 14 | private static readonly Dictionary ErrorMap = new Dictionary(); 15 | 16 | #endregion 17 | 18 | #region Constructors and Destructors 19 | 20 | static JsonErrorCodes() 21 | { 22 | ErrorMap.Add(ResponseStatus.NoSuchElement, "no such element"); 23 | ErrorMap.Add(ResponseStatus.NoSuchFrame, "no such frame"); 24 | ErrorMap.Add(ResponseStatus.UnknownCommand, "unknown command"); 25 | ErrorMap.Add(ResponseStatus.StaleElementReference, "stale element reference"); 26 | ErrorMap.Add(ResponseStatus.ElementNotVisible, "element not visible"); 27 | ErrorMap.Add(ResponseStatus.InvalidElementState, "invalid element state"); 28 | ErrorMap.Add(ResponseStatus.UnknownError, "unknown error"); 29 | ErrorMap.Add(ResponseStatus.ElementIsNotSelectable, "element not selectable"); 30 | ErrorMap.Add(ResponseStatus.JavaScriptError, "javascript error"); 31 | ErrorMap.Add(ResponseStatus.Timeout, "timeout"); 32 | ErrorMap.Add(ResponseStatus.NoSuchWindow, "no such window"); 33 | ErrorMap.Add(ResponseStatus.InvalidCookieDomain, "invalid cookie domain"); 34 | ErrorMap.Add(ResponseStatus.UnableToSetCookie, "unable to set cookie"); 35 | ErrorMap.Add(ResponseStatus.UnexpectedAlertOpen, "unexpected alert open"); 36 | ErrorMap.Add(ResponseStatus.NoAlertOpenError, "no such alert"); 37 | ErrorMap.Add(ResponseStatus.ScriptTimeout, "script timeout"); 38 | ErrorMap.Add(ResponseStatus.InvalidElementCoordinates, "invalid element coordinates"); 39 | ErrorMap.Add(ResponseStatus.InvalidSelector, "invalid selector"); 40 | ErrorMap.Add(ResponseStatus.SessionNotCreatedException, "session not created"); 41 | ErrorMap.Add(ResponseStatus.MoveTargetOutOfBounds, "move target out of bounds"); 42 | 43 | // TODO: No match in ResponseStatus 44 | /*ErrorMap.Add(400, "invalid argument"); 45 | ErrorMap.Add(404, "invalid session id"); 46 | ErrorMap.Add(405, "unknown method"); 47 | ErrorMap.Add(500, "unsupported operation");*/ 48 | } 49 | 50 | #endregion 51 | 52 | #region Public Methods and Operators 53 | 54 | public static string Parse(ResponseStatus status) 55 | { 56 | return ErrorMap.ContainsKey(status) ? ErrorMap[status] : status.ToString(); 57 | } 58 | 59 | #endregion 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/JsonWireClasses.cs: -------------------------------------------------------------------------------- 1 | // 2 | namespace Winium.StoreApps.Common 3 | { 4 | #region 5 | 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | using Newtonsoft.Json; 10 | 11 | #endregion 12 | 13 | public class JsonElementContent 14 | { 15 | #region Constructors and Destructors 16 | 17 | public JsonElementContent(string element) 18 | { 19 | this.Element = element; 20 | } 21 | 22 | #endregion 23 | 24 | #region Public Properties 25 | 26 | [JsonProperty("ELEMENT")] 27 | public string Element { get; set; } 28 | 29 | #endregion 30 | } 31 | 32 | public class JsonResponse 33 | { 34 | #region Constructors and Destructors 35 | 36 | public JsonResponse(string sessionId, ResponseStatus responseCode, object value) 37 | { 38 | this.SessionId = sessionId; 39 | this.Status = responseCode; 40 | 41 | this.Value = responseCode == ResponseStatus.Success ? value : this.PrepareErrorResponse(value); 42 | } 43 | 44 | private object PrepareErrorResponse(object value) 45 | { 46 | var result = new Dictionary { { "error", JsonErrorCodes.Parse(this.Status) } }; 47 | 48 | string message; 49 | var exception = value as Exception; 50 | if (exception != null) 51 | { 52 | message = exception.Message; 53 | result.Add("stacktrace", exception.StackTrace); 54 | } 55 | else 56 | { 57 | message = value.ToString(); 58 | } 59 | 60 | result.Add("message", message); 61 | return result; 62 | } 63 | 64 | #endregion 65 | 66 | #region Public Properties 67 | 68 | [JsonProperty("sessionId")] 69 | public string SessionId { get; set; } 70 | 71 | [JsonProperty("status")] 72 | public ResponseStatus Status { get; set; } 73 | 74 | [JsonProperty("value")] 75 | public object Value { get; set; } 76 | 77 | #endregion 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region 2 | 3 | using System.Reflection; 4 | using System.Resources; 5 | 6 | #endregion 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | [assembly: AssemblyTitle("Winium.StoreApps.Common")] 12 | [assembly: AssemblyDescription("")] 13 | [assembly: AssemblyConfiguration("")] 14 | [assembly: AssemblyCompany("")] 15 | [assembly: AssemblyProduct("Winium.StoreApps.Common")] 16 | [assembly: AssemblyCopyright("Copyright © 2015")] 17 | [assembly: AssemblyTrademark("")] 18 | [assembly: AssemblyCulture("")] 19 | [assembly: NeutralResourcesLanguage("en")] 20 | 21 | // Version information for an assembly consists of the following four values: 22 | // Major Version 23 | // Minor Version 24 | // Build Number 25 | // Revision 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.*")] 30 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/ResponseStatus.cs: -------------------------------------------------------------------------------- 1 | namespace Winium.StoreApps.Common 2 | { 3 | public enum ResponseStatus 4 | { 5 | Success = 0, 6 | 7 | NoSuchDriver = 6, 8 | 9 | NoSuchElement = 7, 10 | 11 | NoSuchFrame = 8, 12 | 13 | UnknownCommand = 9, 14 | 15 | StaleElementReference = 10, 16 | 17 | ElementNotVisible = 11, 18 | 19 | InvalidElementState = 12, 20 | 21 | UnknownError = 13, 22 | 23 | ElementIsNotSelectable = 15, 24 | 25 | JavaScriptError = 17, 26 | 27 | XPathLookupError = 19, 28 | 29 | Timeout = 21, 30 | 31 | NoSuchWindow = 23, 32 | 33 | InvalidCookieDomain = 24, 34 | 35 | UnableToSetCookie = 25, 36 | 37 | UnexpectedAlertOpen = 26, 38 | 39 | NoAlertOpenError = 27, 40 | 41 | ScriptTimeout = 28, 42 | 43 | InvalidElementCoordinates = 29, 44 | 45 | ImeNotAvailable = 30, 46 | 47 | ImeEngineActivationFailed = 31, 48 | 49 | InvalidSelector = 32, 50 | 51 | SessionNotCreatedException = 33, 52 | 53 | MoveTargetOutOfBounds = 34 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/Winium.StoreApps.Common.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 12.0 6 | Debug 7 | AnyCPU 8 | {3C8D0B9C-576B-4778-97B1-6839AA944AEE} 9 | Library 10 | Properties 11 | Winium.StoreApps.Common 12 | Winium.StoreApps.Common 13 | en-US 14 | 512 15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | Profile151 17 | v4.6 18 | ..\ 19 | true 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | 30 | 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | ..\packages\Newtonsoft.Json.6.0.8\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 64 | 65 | 66 | 67 | 74 | -------------------------------------------------------------------------------- /src/Winium.StoreApps.Common/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Winium.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Winium.Desktop.Driver", "Winium.Desktop.Driver\Winium.Desktop.Driver.csproj", "{B214C2BA-43FA-486F-AD0B-D4890C1748C0}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{56A74D50-0B52-4130-BF77-C5BD2B3441A6}" 9 | ProjectSection(SolutionItems) = preProject 10 | Settings.StyleCop = Settings.StyleCop 11 | Winium.sln.DotSettings = Winium.sln.DotSettings 12 | EndProjectSection 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Winium.StoreApps.Common", "Winium.StoreApps.Common\Winium.StoreApps.Common.csproj", "{3C8D0B9C-576B-4778-97B1-6839AA944AEE}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{7F1DBF6F-6390-429F-BAD0-08D85DE19E0C}" 17 | ProjectSection(SolutionItems) = preProject 18 | .nuget\NuGet.Config = .nuget\NuGet.Config 19 | .nuget\NuGet.targets = .nuget\NuGet.targets 20 | EndProjectSection 21 | EndProject 22 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestApps.Tests", "TestApps.Tests", "{EAE7A411-86B1-4AD5-BF33-81F60CD1A8FC}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsFormsTestApplication.Tests", "TestApps.Tests\WindowsFormsTestApplication.Tests\WindowsFormsTestApplication.Tests.csproj", "{DC69009A-39E7-4F02-B721-3CC99B4EA637}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfTestApplication.Tests", "TestApps.Tests\WpfTestApplication.Tests\WpfTestApplication.Tests.csproj", "{8B4DB0CD-0853-43A4-8E45-EB7080C1DCD7}" 27 | EndProject 28 | Global 29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 30 | Debug|Any CPU = Debug|Any CPU 31 | Release|Any CPU = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {B214C2BA-43FA-486F-AD0B-D4890C1748C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {B214C2BA-43FA-486F-AD0B-D4890C1748C0}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {B214C2BA-43FA-486F-AD0B-D4890C1748C0}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {B214C2BA-43FA-486F-AD0B-D4890C1748C0}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {3C8D0B9C-576B-4778-97B1-6839AA944AEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {3C8D0B9C-576B-4778-97B1-6839AA944AEE}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {3C8D0B9C-576B-4778-97B1-6839AA944AEE}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {3C8D0B9C-576B-4778-97B1-6839AA944AEE}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {DC69009A-39E7-4F02-B721-3CC99B4EA637}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {DC69009A-39E7-4F02-B721-3CC99B4EA637}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {DC69009A-39E7-4F02-B721-3CC99B4EA637}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {DC69009A-39E7-4F02-B721-3CC99B4EA637}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {8B4DB0CD-0853-43A4-8E45-EB7080C1DCD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {8B4DB0CD-0853-43A4-8E45-EB7080C1DCD7}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {8B4DB0CD-0853-43A4-8E45-EB7080C1DCD7}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {8B4DB0CD-0853-43A4-8E45-EB7080C1DCD7}.Release|Any CPU.Build.0 = Release|Any CPU 50 | EndGlobalSection 51 | GlobalSection(SolutionProperties) = preSolution 52 | HideSolutionNode = FALSE 53 | EndGlobalSection 54 | GlobalSection(NestedProjects) = preSolution 55 | {DC69009A-39E7-4F02-B721-3CC99B4EA637} = {EAE7A411-86B1-4AD5-BF33-81F60CD1A8FC} 56 | {8B4DB0CD-0853-43A4-8E45-EB7080C1DCD7} = {EAE7A411-86B1-4AD5-BF33-81F60CD1A8FC} 57 | EndGlobalSection 58 | EndGlobal 59 | --------------------------------------------------------------------------------