From d7756298aab5863e03a23ebc684a58cc51720572 Mon Sep 17 00:00:00 2001 From: Frederic Forjan Date: Tue, 10 Dec 2019 13:30:36 -0800 Subject: [PATCH] add NotepadCalculatorTest sample (#903) --- .../CalculatorSession.cs | 85 +++++++++++++ .../NotepadAndCalculatorTest/MultiSession.cs | 74 +++++++++++ .../NotepadCalculatorTest.csproj | 120 ++++++++++++++++++ .../NotepadCalculatorTest.sln | 25 ++++ .../NotepadSession.cs | 82 ++++++++++++ .../Properties/AssemblyInfo.cs | 52 ++++++++ Samples/C#/NotepadAndCalculatorTest/README.md | 33 +++++ .../NotepadAndCalculatorTest/SingleSession.cs | 80 ++++++++++++ .../NotepadAndCalculatorTest/packages.config | 10 ++ 9 files changed, 561 insertions(+) create mode 100644 Samples/C#/NotepadAndCalculatorTest/CalculatorSession.cs create mode 100644 Samples/C#/NotepadAndCalculatorTest/MultiSession.cs create mode 100644 Samples/C#/NotepadAndCalculatorTest/NotepadCalculatorTest.csproj create mode 100644 Samples/C#/NotepadAndCalculatorTest/NotepadCalculatorTest.sln create mode 100644 Samples/C#/NotepadAndCalculatorTest/NotepadSession.cs create mode 100644 Samples/C#/NotepadAndCalculatorTest/Properties/AssemblyInfo.cs create mode 100644 Samples/C#/NotepadAndCalculatorTest/README.md create mode 100644 Samples/C#/NotepadAndCalculatorTest/SingleSession.cs create mode 100644 Samples/C#/NotepadAndCalculatorTest/packages.config diff --git a/Samples/C#/NotepadAndCalculatorTest/CalculatorSession.cs b/Samples/C#/NotepadAndCalculatorTest/CalculatorSession.cs new file mode 100644 index 00000000..60810be5 --- /dev/null +++ b/Samples/C#/NotepadAndCalculatorTest/CalculatorSession.cs @@ -0,0 +1,85 @@ +//****************************************************************************** +// +// 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 NotepadCalculatorTest +{ + public class CalculatorSession : IDisposable + { + // 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_8wekyb3d8bbwe!App"; + + public WindowsDriver Session { get; private set; } + public WindowsElement CalculatorHeader { get; private set; } + public WindowsElement CalculatorResult { get; private set; } + + public CalculatorSession() + { + // 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"); + this.Session = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), appCapabilities); + Assert.IsNotNull(Session); + + // Set implicit timeout to 1.5 seconds to make element search to retry every 500 ms for at most three times + Session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1.5); + + // Identify calculator mode by locating the calculator header + try + { + CalculatorHeader = Session.FindElementByAccessibilityId("Header"); + } + catch + { + CalculatorHeader = Session.FindElementByAccessibilityId("ContentPresenter"); + } + + // Ensure that calculator is in standard mode + if (!CalculatorHeader.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(CalculatorHeader.Text.Equals("Standard", StringComparison.OrdinalIgnoreCase)); + } + + // Locate the CalculatorResult element + CalculatorResult = Session.FindElementByAccessibilityId("CalculatorResults"); + } + + public void Dispose() + { + // Close the application and delete the session + if (Session != null) + { + Session.Quit(); + Session = null; + CalculatorHeader = null; + CalculatorResult = null; + } + } + } +} diff --git a/Samples/C#/NotepadAndCalculatorTest/MultiSession.cs b/Samples/C#/NotepadAndCalculatorTest/MultiSession.cs new file mode 100644 index 00000000..5f1cee79 --- /dev/null +++ b/Samples/C#/NotepadAndCalculatorTest/MultiSession.cs @@ -0,0 +1,74 @@ +//****************************************************************************** +// +// 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; +using System.Runtime.CompilerServices; + +namespace NotepadCalculatorTest +{ + [TestClass] + public class MultiSession + { + private NotepadSession notepadSession; + private CalculatorSession calculatorSession; + + [TestMethod] + [DataRow("One", "Plus", "Seven")] + [DataRow("Nine", "Minus", "One")] + [DataRow("Eight", "Divide by", "Eight")] + public void Templatized(string input1, string operation, string input2) + { + // we (re) start with our notepad session + notepadSession.Session.SwitchTo(); + notepadSession.NotepadMainEditBox.SendKeys($"{input1} {operation} {input2} = "); + + // now let's switch to calculator + calculatorSession.Session.SwitchTo(); + + // Run sequence of button presses specified above and validate the results + calculatorSession.Session.FindElementByName(input1).Click(); + calculatorSession.Session.FindElementByName(operation).Click(); + calculatorSession.Session.FindElementByName(input2).Click(); + calculatorSession.Session.FindElementByName("Equals").Click(); + + // and back to notepad for the result + notepadSession.Session.SwitchTo(); + notepadSession.NotepadMainEditBox.SendKeys($"{GetCalculatorResultText()}\n"); + } + + [TestInitialize] + public void TestInitialize() + { + notepadSession = new NotepadSession(); + calculatorSession = new CalculatorSession(); + } + + [TestCleanup] + public void TestCleanup() + { + calculatorSession.Dispose(); + notepadSession.Dispose(); + } + + private string GetCalculatorResultText() + { + return calculatorSession.CalculatorResult.Text.Replace("Display is", string.Empty).Trim(); + } + } +} diff --git a/Samples/C#/NotepadAndCalculatorTest/NotepadCalculatorTest.csproj b/Samples/C#/NotepadAndCalculatorTest/NotepadCalculatorTest.csproj new file mode 100644 index 00000000..fe528dcd --- /dev/null +++ b/Samples/C#/NotepadAndCalculatorTest/NotepadCalculatorTest.csproj @@ -0,0 +1,120 @@ + + + + + Debug + AnyCPU + {B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F} + Library + Properties + NotepadCalculatorTest + NotepadCalculatorTest + 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.1.2.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll + + + packages\MSTest.TestFramework.1.2.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + + + packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + packages\Selenium.WebDriver.3.8.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/Samples/C#/NotepadAndCalculatorTest/NotepadCalculatorTest.sln b/Samples/C#/NotepadAndCalculatorTest/NotepadCalculatorTest.sln new file mode 100644 index 00000000..1e9cd586 --- /dev/null +++ b/Samples/C#/NotepadAndCalculatorTest/NotepadCalculatorTest.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29326.143 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotepadCalculatorTest", "NotepadCalculatorTest.csproj", "{B2C5ADFF-D6B5-48C1-BB8C-571BFD583D7F}" +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 = {993F4E37-F1F7-434A-BFF8-F767326C7654} + EndGlobalSection +EndGlobal diff --git a/Samples/C#/NotepadAndCalculatorTest/NotepadSession.cs b/Samples/C#/NotepadAndCalculatorTest/NotepadSession.cs new file mode 100644 index 00000000..2579ca50 --- /dev/null +++ b/Samples/C#/NotepadAndCalculatorTest/NotepadSession.cs @@ -0,0 +1,82 @@ +//****************************************************************************** +// +// 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 OpenQA.Selenium; +using System; + +namespace NotepadCalculatorTest +{ + public class NotepadSession :IDisposable + { + private const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723"; + private const string NotepadAppId = @"C:\Windows\System32\notepad.exe"; + + public WindowsElement NotepadMainEditBox { get; private set; } + + public NotepadSession() + { + + // Create a new session to launch Notepad application + DesiredCapabilities appCapabilities = new DesiredCapabilities(); + appCapabilities.SetCapability("app", NotepadAppId); + this.Session = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), appCapabilities); + Assert.IsNotNull(Session); + Assert.IsNotNull(Session.SessionId); + + // Verify that Notepad is started with untitled new file + Assert.AreEqual("Untitled - Notepad", Session.Title); + + // Set implicit timeout to 1.5 seconds to make element search to retry every 500 ms for at most three times + Session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1.5); + + NotepadMainEditBox = Session.FindElementByClassName("Edit"); + } + + + public void Cleanup() + { + // Select all text and delete to clear the edit box + NotepadMainEditBox.SendKeys(Keys.Control + "a" + Keys.Control); + NotepadMainEditBox.SendKeys(Keys.Delete); + Assert.AreEqual(string.Empty, NotepadMainEditBox.Text); + } + + public WindowsDriver Session { get; } + + public void Dispose() + { + // Close the application and delete the session + if (Session != null) + { + NotepadMainEditBox = null; + + Session.Close(); + + try + { + // Dismiss Save dialog if it is blocking the exit + Session.FindElementByName("Don't Save").Click(); + } + catch { } + + Session.Quit(); + } + } + } +} \ No newline at end of file diff --git a/Samples/C#/NotepadAndCalculatorTest/Properties/AssemblyInfo.cs b/Samples/C#/NotepadAndCalculatorTest/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..98d094f3 --- /dev/null +++ b/Samples/C#/NotepadAndCalculatorTest/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("NotepadCalculatorTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NotepadCalculatorTest")] +[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-571bfd583d7e")] + +// 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/Samples/C#/NotepadAndCalculatorTest/README.md b/Samples/C#/NotepadAndCalculatorTest/README.md new file mode 100644 index 00000000..44c1144d --- /dev/null +++ b/Samples/C#/NotepadAndCalculatorTest/README.md @@ -0,0 +1,33 @@ +# NotepadCalculatorTest + +NotepadCalculatorTest is a sample test project that runs and validates basic UI scenario on Windows 10 using 2 built-in application, **Calculator** And **Notepad**. + +This test project highlights the following basic interactions to demonstrate how UI testing using Windows Application Driver work. +- Switching between session while working with 2 applications in single session +- Switching between session while working with 2 applications in multi session + +## 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 `NotepadCalculatorTest.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* + +## Adding/Updating Test Scenario + +Please follow the guidelines below to maintain test reliability and conciseness: +1. Test all changes against all supported version of Windows 10 built-in **Calculator** and **Notepad** app +2. Maintain simplicity and only add tests that provide additional value to the sample diff --git a/Samples/C#/NotepadAndCalculatorTest/SingleSession.cs b/Samples/C#/NotepadAndCalculatorTest/SingleSession.cs new file mode 100644 index 00000000..e118fc79 --- /dev/null +++ b/Samples/C#/NotepadAndCalculatorTest/SingleSession.cs @@ -0,0 +1,80 @@ +//****************************************************************************** +// +// 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; +using System.Runtime.CompilerServices; + +namespace NotepadCalculatorTest +{ + [TestClass] + public class SingleSession + { + private static NotepadSession notepadSession; + private static CalculatorSession calculatorSession; + + [TestMethod] + [DataRow("One", "Plus", "Seven")] + [DataRow("Nine", "Minus", "One")] + [DataRow("Eight", "Divide by", "Eight")] + public void Templatized(string input1, string operation, string input2) + { + // we (re) start with our notepad session + notepadSession.Session.SwitchTo(); + notepadSession.NotepadMainEditBox.SendKeys($"{input1} {operation} {input2} = "); + + // now let's switch to calculator + calculatorSession.Session.SwitchTo(); + + // Run sequence of button presses specified above and validate the results + calculatorSession.Session.FindElementByName(input1).Click(); + calculatorSession.Session.FindElementByName(operation).Click(); + calculatorSession.Session.FindElementByName(input2).Click(); + calculatorSession.Session.FindElementByName("Equals").Click(); + + // and back to notepad for the result + notepadSession.Session.SwitchTo(); + notepadSession.NotepadMainEditBox.SendKeys($"{GetCalculatorResultText()}\n"); + } + + [TestInitialize] + public void TestInitialize() + { + notepadSession.Cleanup(); + } + + [ClassInitialize] + public static void ClassInitialize(TestContext testContext) + { + notepadSession = new NotepadSession(); + calculatorSession = new CalculatorSession(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + calculatorSession.Dispose(); + notepadSession.Dispose(); + } + + private string GetCalculatorResultText() + { + return calculatorSession.CalculatorResult.Text.Replace("Display is", string.Empty).Trim(); + } + } +} diff --git a/Samples/C#/NotepadAndCalculatorTest/packages.config b/Samples/C#/NotepadAndCalculatorTest/packages.config new file mode 100644 index 00000000..0512948e --- /dev/null +++ b/Samples/C#/NotepadAndCalculatorTest/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file