diff --git a/src/CalculatorWADTests/CalculatorSession.cs b/src/CalculatorWADTests/CalculatorSession.cs new file mode 100644 index 00000000..de297391 --- /dev/null +++ b/src/CalculatorWADTests/CalculatorSession.cs @@ -0,0 +1,60 @@ +//****************************************************************************** +// +// Copyright (c) 2017 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium.Appium.Windows; +using OpenQA.Selenium.Remote; +using System; +using System.Threading; + +namespace CalculatorTest +{ + public class CalculatorSession + { + // Note: append /wd/hub to the URL if you're directing the test at Appium + private const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723"; + private const string CalculatorAppId = "Microsoft.WindowsCalculator.Dev_8wekyb3d8bbwe!App"; + protected static WindowsDriver session; + + public static void Setup(TestContext context) + { + // Launch Calculator application if it is not yet launched + if (session == null) + { + // Create a new session to bring up an instance of the Calculator application + // Note: Multiple calculator windows (instances) share the same process Id + DesiredCapabilities appCapabilities = new DesiredCapabilities(); + appCapabilities.SetCapability("app", CalculatorAppId); + appCapabilities.SetCapability("deviceName", "WindowsPC"); + session = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), appCapabilities); + Thread.Sleep(150000); + Assert.IsNotNull(session); + // Set implicit timeout to 5 seconds to make element search to retry every 500 ms for at most three times + session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5); + } + } + + public static void TearDown() + { + // Close the application and delete the session + if (session != null) + { + session.Quit(); + session = null; + } + } + } +} diff --git a/src/CalculatorWADTests/CalculatorTest.csproj b/src/CalculatorWADTests/CalculatorTest.csproj new file mode 100644 index 00000000..c1e149b2 --- /dev/null +++ b/src/CalculatorWADTests/CalculatorTest.csproj @@ -0,0 +1,118 @@ + + + + + + Debug + AnyCPU + {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F} + Library + Properties + CalculatorTest + CalculatorTest + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Microsoft.WinAppDriver.Appium.WebDriver.1.0.1-Preview\lib\net45\appium-dotnet-driver.dll + + + packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + + ..\..\packages\MSTest.TestFramework.2.0.0-beta2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll + + + ..\..\packages\MSTest.TestFramework.2.0.0-beta2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + + + packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + ..\..\packages\Selenium.WebDriver.3.141.0\lib\net45\WebDriver.dll + + + ..\..\packages\Selenium.Support.3.8.0\lib\net45\WebDriver.Support.dll + + + + + + + + + + + + + + + + + + + + + + + False + + + False + + + False + + + False + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + \ No newline at end of file diff --git a/src/CalculatorWADTests/CalculatorTest.sln b/src/CalculatorWADTests/CalculatorTest.sln new file mode 100644 index 00000000..807e2150 --- /dev/null +++ b/src/CalculatorWADTests/CalculatorTest.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.2036 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorTest", "CalculatorTest.csproj", "{B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EF2AC85C-90D3-43B4-AEAC-66911DF8208F}" + ProjectSection(SolutionItems) = preProject + TestSettings1.runsettings = TestSettings1.runsettings + TestSettings1.testsettings = TestSettings1.testsettings + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9F92CA6B-460C-4D04-A522-8A92BC33B686} + EndGlobalSection +EndGlobal diff --git a/src/CalculatorWADTests/Properties/AssemblyInfo.cs b/src/CalculatorWADTests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..e958baef --- /dev/null +++ b/src/CalculatorWADTests/Properties/AssemblyInfo.cs @@ -0,0 +1,52 @@ +//****************************************************************************** +// +// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CalculatorTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CalculatorTest")] +[assembly: AssemblyCopyright("Copyright © 2016 Microsoft Corporation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b2c5adff-d6b5-48c1-bb8c-571bfd583d7f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/CalculatorWADTests/README.md b/src/CalculatorWADTests/README.md new file mode 100644 index 00000000..b35a93d1 --- /dev/null +++ b/src/CalculatorWADTests/README.md @@ -0,0 +1,33 @@ +# CalculatorTest + +CalculatorTest is a sample test project that runs and validates basic UI scenarios on the **Microsoft Open Sourced Calculator** application. This sample is created as the most basic test project to quickly try out Windows Application Driver. + +This test project highlights the following basic interactions to demonstrate how UI testing using Windows Application Driver work. +- Creating a modern UWP app session +- Finding element using name +- Finding element using accessibility id +- Finding element using XPath +- Sending click action to an element +- Retrieving element value +- Navigating using SplitViewPane + + +## Requirements + +- Windows 10 PC with the latest Windows 10 version (Version 1809 or later) +- Microsoft Visual Studio 2017 or later + + +## Getting Started + +1. [Run](../../../README.md#installing-and-running-windows-application-driver) `WinAppDriver.exe` on the test device +2. Open `CalculatorTest.sln` in Visual Studio +3. Select **Build** > **Rebuild Solution** +4. Select **Test** > **Windows** > **Test Explorer** +5. Select **Run All** on the test pane or through menu **Test** > **Run** > **All Tests** + +> Once the project is successfully built, you can use the **TestExplorer** to pick and choose the test scenario(s) to run + +> If Visual Studio fail to discover and run the test scenarios: +> 1. Select **Tools** > **Options...** > **Test** +> 2. Under *Active Solution*, uncheck *For improved performance, only use test adapters in test assembly folder or as specified in runsettings file* diff --git a/src/CalculatorWADTests/ScenarioStandard.cs b/src/CalculatorWADTests/ScenarioStandard.cs new file mode 100644 index 00000000..5c78614c --- /dev/null +++ b/src/CalculatorWADTests/ScenarioStandard.cs @@ -0,0 +1,160 @@ +//****************************************************************************** +// +// Copyright (c) 2017 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium.Appium.Windows; +using System.Threading; +using System; + +namespace CalculatorTest +{ + [TestClass] + public class ScenarioStandard : CalculatorSession + { + private static WindowsElement header; + private static WindowsElement calculatorResult; + + [TestMethod] + public void Addition() + { + Thread.Sleep(5000); + // Find the buttons by their names and click them in sequence to peform 1 + 7 = 8 + session.FindElementByName("One").Click(); + session.FindElementByName("Plus").Click(); + session.FindElementByName("Seven").Click(); + session.FindElementByName("Equals").Click(); + Assert.AreEqual("8", GetCalculatorResultText()); + } + + [TestMethod] + public void Division() + { + Thread.Sleep(5000); + // Find the buttons by their accessibility ids and click them in sequence to perform 88 / 11 = 8 + session.FindElementByAccessibilityId("num8Button").Click(); + session.FindElementByAccessibilityId("num8Button").Click(); + session.FindElementByAccessibilityId("divideButton").Click(); + session.FindElementByAccessibilityId("num1Button").Click(); + session.FindElementByAccessibilityId("num1Button").Click(); + session.FindElementByAccessibilityId("equalButton").Click(); + Assert.AreEqual("8", GetCalculatorResultText()); + } + + [TestMethod] + public void Multiplication() + { + Thread.Sleep(5000); + // Find the buttons by their names using XPath and click them in sequence to perform 9 x 9 = 81 + session.FindElementByXPath("//Button[@Name='Nine']").Click(); + session.FindElementByXPath("//Button[@Name='Multiply by']").Click(); + session.FindElementByXPath("//Button[@Name='Nine']").Click(); + session.FindElementByXPath("//Button[@Name='Equals']").Click(); + Assert.AreEqual("81", GetCalculatorResultText()); + } + + [TestMethod] + public void Subtraction() + { + Thread.Sleep(5000); + // Find the buttons by their accessibility ids using XPath and click them in sequence to perform 9 - 1 = 8 + session.FindElementByXPath("//Button[@AutomationId=\"num9Button\"]").Click(); + session.FindElementByXPath("//Button[@AutomationId=\"minusButton\"]").Click(); + session.FindElementByXPath("//Button[@AutomationId=\"num1Button\"]").Click(); + session.FindElementByXPath("//Button[@AutomationId=\"equalButton\"]").Click(); + Assert.AreEqual("8", GetCalculatorResultText()); + } + + /* + [TestMethod] + public void Templatized() + { + Templatized("One", "Plus", "Seven", "8"); + Templatized("Nine", "Minus", "One", "8"); + Templatized("Eight", "Divide by", "Eight", "1"); + } + */ + [TestMethod] + [DataRow("One", "Plus", "Seven", "8")] + [DataRow("Nine", "Minus", "One", "8")] + [DataRow("Eight", "Divide by", "Eight", "1")] + public void Templatized(string input1, string operation, string input2, string expectedResult) + { + Thread.Sleep(5000); + // Run sequence of button presses specified above and validate the results + session.FindElementByName(input1).Click(); + session.FindElementByName(operation).Click(); + session.FindElementByName(input2).Click(); + session.FindElementByName("Equals").Click(); + Assert.AreEqual(expectedResult, GetCalculatorResultText()); + } + + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + // Create session to launch a Calculator window + Setup(context); + + Thread.Sleep(5000); + + // Identify calculator mode by locating the header + try + { + header = session.FindElementByAccessibilityId("Header"); + } + catch + { + header = session.FindElementByAccessibilityId("ContentPresenter"); + } + + // Ensure that calculator is in standard mode + if (!header.Text.Equals("Standard", StringComparison.OrdinalIgnoreCase)) + { + session.FindElementByAccessibilityId("TogglePaneButton").Click(); + Thread.Sleep(TimeSpan.FromSeconds(1)); + var splitViewPane = session.FindElementByClassName("SplitViewPane"); + splitViewPane.FindElementByName("Standard Calculator").Click(); + Thread.Sleep(TimeSpan.FromSeconds(1)); + Assert.IsTrue(header.Text.Equals("Standard", StringComparison.OrdinalIgnoreCase)); + } + + Thread.Sleep(5000); + + // Locate the calculatorResult element + calculatorResult = session.FindElementByAccessibilityId("CalculatorResults"); + Assert.IsNotNull(calculatorResult); + } + + [ClassCleanup] + public static void ClassCleanup() + { + TearDown(); + } + + [TestInitialize] + public void Clear() + { + Thread.Sleep(5000); + session.FindElementByName("Clear").Click(); + Assert.AreEqual("0", GetCalculatorResultText()); + Thread.Sleep(10000); + } + + private string GetCalculatorResultText() + { + return calculatorResult.Text.Replace("Display is", string.Empty).Trim(); + } + } +} diff --git a/src/CalculatorWADTests/TestSettings1.runsettings b/src/CalculatorWADTests/TestSettings1.runsettings new file mode 100644 index 00000000..a1bb55c6 --- /dev/null +++ b/src/CalculatorWADTests/TestSettings1.runsettings @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + false + + + diff --git a/src/CalculatorWADTests/packages.config b/src/CalculatorWADTests/packages.config new file mode 100644 index 00000000..92723ea8 --- /dev/null +++ b/src/CalculatorWADTests/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file