Skip to content

Commit f93ba7a

Browse files
committed
Merged PR 583517: Complete unit test for every API endpoint we support on PC Desktop
Create new unit tests for the following API endpoints: - POST /session/:sessionId/element/active API endpoint - GET /session/:sessionId/element/:id/equals/:other API endpoint - GET /session/:sessionId/element/:id/enabled API endpoint - GET /session/:sessionId/element/:id/location API endpoint - GET /session/:sessionId/element/:id/location_in_view API endpoint - GET /session/:sessionId/element/:id/name API endpoint - GET /session/:sessionId/element/:id/size API endpoint - GET /session/:sessionId/element/:id/text API endpoint - POST /session/:sessionId/element/:id/clear API endpoint - POST /session/:sessionId/element/:id/click API endpoint Create a new Utility class containing helper functions to create session, get orphaned element etc Create a new app session base for calculator app with extensive error case scenarios Rename TouchBase to EdgeBase and group all app session base classes in a folder Add common ErrorStrings class in CommonTestSettings Add missing error scenario for various element API endpoint test Add a helper function in AlarmClockBase to recreate stale element scenario Optimize unit tests inheriting AlarmClockBase and CalculatorBase to re-use existing sessions Related work items: #9226712
2 parents 23fdaaa + fe10406 commit f93ba7a

36 files changed

+1527
-268
lines changed

Tests/W3CWebDriver/AlarmClockBase.cs renamed to Tests/W3CWebDriver/AppSessionBase/AlarmClockBase.cs

+43-13
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,18 @@ public class AlarmClockBase
2929

3030
public static void Setup(TestContext context)
3131
{
32-
// Cleanup leftover objects from previous test if exists
33-
TearDown();
34-
35-
// Launch Alarm Clock
36-
DesiredCapabilities appCapabilities = new DesiredCapabilities();
37-
appCapabilities.SetCapability("app", CommonTestSettings.AlarmClockAppId);
38-
session = new WindowsDriver<WindowsElement>(new Uri(CommonTestSettings.WindowsApplicationDriverUrl), appCapabilities);
39-
Assert.IsNotNull(session);
40-
Assert.IsNotNull(session.SessionId);
41-
42-
// Initialize touch screen object
43-
touchScreen = new RemoteTouchScreen(session);
44-
Assert.IsNotNull(touchScreen);
32+
// Launch Alarm Clock if it is not yet launched
33+
if (session == null || touchScreen == null || !CurrentWindowIsAlive())
34+
{
35+
TearDown();
36+
session = Utility.CreateNewSession(CommonTestSettings.AlarmClockAppId);
37+
Assert.IsNotNull(session);
38+
Assert.IsNotNull(session.SessionId);
39+
40+
// Initialize touch screen object
41+
touchScreen = new RemoteTouchScreen(session);
42+
Assert.IsNotNull(touchScreen);
43+
}
4544
}
4645

4746
public static void TearDown()
@@ -83,6 +82,27 @@ protected void AddAlarmEntry(string alarmName)
8382
session.FindElementByAccessibilityId("AlarmSaveButton").Click();
8483
}
8584

85+
private static bool CurrentWindowIsAlive()
86+
{
87+
bool windowIsAlive = false;
88+
89+
if (session != null)
90+
{
91+
try
92+
{
93+
windowIsAlive = !String.IsNullOrEmpty(session.CurrentWindowHandle) && session.CurrentWindowHandle != "0";
94+
windowIsAlive = true;
95+
}
96+
catch
97+
{
98+
session.Quit();
99+
session = null;
100+
}
101+
}
102+
103+
return windowIsAlive;
104+
}
105+
86106
protected void DeletePreviouslyCreatedAlarmEntry(string alarmName)
87107
{
88108
while (true)
@@ -120,5 +140,15 @@ protected void CreateStopwatchLapEntries(uint numberOfEntry)
120140
}
121141
stopwatchPlayPauseButton.Click();
122142
}
143+
144+
protected static WindowsElement GetStaleElement()
145+
{
146+
// Open the add alarm page, locate the cancel button, and click it to get a stale cancel button
147+
session.FindElementByAccessibilityId("AddAlarmButton").Click();
148+
WindowsElement staleElement = session.FindElementByAccessibilityId("CancelButton");
149+
staleElement.Click();
150+
System.Threading.Thread.Sleep(1000);
151+
return staleElement;
152+
}
123153
}
124154
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//******************************************************************************
2+
//
3+
// Copyright (c) 2017 Microsoft Corporation. All rights reserved.
4+
//
5+
// This code is licensed under the MIT License (MIT).
6+
//
7+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13+
// THE SOFTWARE.
14+
//
15+
//******************************************************************************
16+
17+
using Microsoft.VisualStudio.TestTools.UnitTesting;
18+
using OpenQA.Selenium.Appium.Windows;
19+
20+
namespace W3CWebDriver
21+
{
22+
public class CalculatorBase
23+
{
24+
protected static WindowsDriver<WindowsElement> session;
25+
private static WindowsElement header;
26+
27+
public static void Setup(TestContext context)
28+
{
29+
// Launch Calculator if it is not yet launched
30+
if (session == null)
31+
{
32+
session = Utility.CreateNewSession(CommonTestSettings.CalculatorAppId);
33+
Assert.IsNotNull(session);
34+
Assert.IsNotNull(session.SessionId);
35+
header = session.FindElementByAccessibilityId("Header");
36+
Assert.IsNotNull(header);
37+
}
38+
39+
// Set focus on the calculator window
40+
header.Click();
41+
42+
// Ensure that calculator is in standard mode
43+
if (!header.Text.Equals("Standard"))
44+
{
45+
session.FindElementByAccessibilityId("NavButton").Click();
46+
System.Threading.Thread.Sleep(1000);
47+
var splitViewPane = session.FindElementByClassName("SplitViewPane");
48+
splitViewPane.FindElementByName("Standard Calculator").Click();
49+
System.Threading.Thread.Sleep(1000);
50+
Assert.AreEqual("Standard", header.Text);
51+
}
52+
}
53+
54+
public static void TearDown()
55+
{
56+
header = null;
57+
58+
// Close the application and delete the session
59+
if (session != null)
60+
{
61+
session.Quit();
62+
session = null;
63+
}
64+
}
65+
66+
protected static WindowsElement GetStaleElement()
67+
{
68+
session.FindElementByAccessibilityId("ClearMemoryButton").Click();
69+
session.FindElementByAccessibilityId("clearButton").Click();
70+
session.FindElementByAccessibilityId("memButton").Click();
71+
72+
try
73+
{
74+
// Locate the Memory pivot item tab that is displayed in expanded mode
75+
session.FindElementByAccessibilityId("MemoryLabel").Click();
76+
}
77+
catch
78+
{
79+
// Open the memory flyout when the calculator is in compact mode
80+
session.FindElementByAccessibilityId("MemoryButton").Click();
81+
}
82+
83+
System.Threading.Thread.Sleep(1000);
84+
WindowsElement staleElement = session.FindElementByAccessibilityId("MemoryListView").FindElementByName("0") as WindowsElement;
85+
session.FindElementByAccessibilityId("ClearMemory").Click();
86+
header.Click(); // Dismiss memory flyout that could be displayed if calculator is in compact mode
87+
System.Threading.Thread.Sleep(1000);
88+
return staleElement;
89+
}
90+
}
91+
}

Tests/W3CWebDriver/CommonTestSettings.cs renamed to Tests/W3CWebDriver/AppSessionBase/CommonTestSettings.cs

+9-3
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,26 @@
1414
//
1515
//******************************************************************************
1616

17-
using Microsoft.VisualStudio.TestTools.UnitTesting;
18-
1917
namespace W3CWebDriver
2018
{
21-
[TestClass]
2219
public class CommonTestSettings
2320
{
2421
public const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
2522
public const string AlarmClockAppId = "Microsoft.WindowsAlarms_8wekyb3d8bbwe!App";
2623
public const string CalculatorAppId = "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App";
24+
public const string DesktopAppId = "Root";
2725
public const string EdgeAppId = "Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge";
2826
public const string ExplorerAppId = @"C:\Windows\System32\explorer.exe";
2927
public const string NotepadAppId = @"C:\Windows\System32\notepad.exe";
3028
public const string MicrosoftUrl = "www.microsoft.com";
3129
public const string GitHubUrl = "https://github.com/Microsoft/WinAppDriver";
3230
}
31+
32+
public class ErrorStrings
33+
{
34+
public const string ElementNotVisible = "An element command could not be completed because the element is not pointer- or keyboard interactable.";
35+
public const string NoSuchElement = "An element could not be located on the page using the given search parameters.";
36+
public const string NoSuchWindow = "Currently selected window has been closed";
37+
public const string StaleElementReference = "An element command failed because the referenced element is no longer attached to the DOM.";
38+
}
3339
}

Tests/W3CWebDriver/TouchBase.cs renamed to Tests/W3CWebDriver/AppSessionBase/EdgeBase.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
namespace W3CWebDriver
2828
{
29-
public class TouchBase
29+
public class EdgeBase
3030
{
3131
protected static WindowsDriver<WindowsElement> session;
3232
protected static RemoteTouchScreen touchScreen;
@@ -39,9 +39,7 @@ public static void Setup(TestContext context)
3939
TearDown();
4040

4141
// Launch the Edge browser app
42-
DesiredCapabilities appCapabilities = new DesiredCapabilities();
43-
appCapabilities.SetCapability("app", CommonTestSettings.EdgeAppId);
44-
session = new WindowsDriver<WindowsElement>(new Uri(CommonTestSettings.WindowsApplicationDriverUrl), appCapabilities);
42+
session = Utility.CreateNewSession(CommonTestSettings.EdgeAppId);
4543
session.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5));
4644
Assert.IsNotNull(session);
4745
Assert.IsNotNull(session.SessionId);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//******************************************************************************
2+
//
3+
// Copyright (c) 2017 Microsoft Corporation. All rights reserved.
4+
//
5+
// This code is licensed under the MIT License (MIT).
6+
//
7+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13+
// THE SOFTWARE.
14+
//
15+
//******************************************************************************
16+
17+
using OpenQA.Selenium.Appium.Windows;
18+
using OpenQA.Selenium.Remote;
19+
using System;
20+
21+
namespace W3CWebDriver
22+
{
23+
public class Utility
24+
{
25+
private static WindowsDriver<WindowsElement> orphanedSession;
26+
private static WindowsElement orphanedElement;
27+
28+
~Utility()
29+
{
30+
CleanupOrphanedSession();
31+
}
32+
33+
public static WindowsDriver<WindowsElement> CreateNewSession(string appId)
34+
{
35+
DesiredCapabilities appCapabilities = new DesiredCapabilities();
36+
appCapabilities.SetCapability("app", appId);
37+
return new WindowsDriver<WindowsElement>(new Uri(CommonTestSettings.WindowsApplicationDriverUrl), appCapabilities);
38+
}
39+
40+
public static WindowsElement GetOrphanedElement()
41+
{
42+
// Re-initialize orphaned session and element if they are compromised
43+
if (orphanedSession == null || orphanedElement == null)
44+
{
45+
InitializeOrphanedSession();
46+
}
47+
48+
return orphanedElement;
49+
}
50+
51+
public static WindowsDriver<WindowsElement> GetOrphanedSession()
52+
{
53+
// Re-initialize orphaned session and element if they are compromised
54+
if (orphanedSession == null || orphanedElement == null)
55+
{
56+
InitializeOrphanedSession();
57+
}
58+
59+
return orphanedSession;
60+
}
61+
62+
private static void CleanupOrphanedSession()
63+
{
64+
orphanedElement = null;
65+
66+
// Cleanup after the session if exists
67+
if (orphanedSession != null)
68+
{
69+
orphanedSession.Quit();
70+
orphanedSession = null;
71+
}
72+
}
73+
74+
private static void InitializeOrphanedSession()
75+
{
76+
// Create new calculator session and close the window to get an orphaned element
77+
CleanupOrphanedSession();
78+
orphanedSession = CreateNewSession(CommonTestSettings.CalculatorAppId);
79+
orphanedElement = orphanedSession.FindElementByAccessibilityId("Header");
80+
orphanedSession.Close();
81+
}
82+
}
83+
}

Tests/W3CWebDriver/Back.cs

+5-20
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ public class Back
2929
[TestMethod]
3030
public void NavigateBackBrowser()
3131
{
32-
DesiredCapabilities appCapabilities = new DesiredCapabilities();
33-
appCapabilities.SetCapability("app", CommonTestSettings.EdgeAppId);
34-
session = new WindowsDriver<WindowsElement>(new Uri(CommonTestSettings.WindowsApplicationDriverUrl), appCapabilities);
32+
session = Utility.CreateNewSession(CommonTestSettings.EdgeAppId);
3533
Assert.IsNotNull(session);
3634
System.Threading.Thread.Sleep(3000); // Sleep for 3 seconds
3735

@@ -59,9 +57,7 @@ public void NavigateBackBrowser()
5957
[TestMethod]
6058
public void NavigateBackModernApp()
6159
{
62-
DesiredCapabilities appCapabilities = new DesiredCapabilities();
63-
appCapabilities.SetCapability("app", CommonTestSettings.AlarmClockAppId);
64-
session = new WindowsDriver<WindowsElement>(new Uri(CommonTestSettings.WindowsApplicationDriverUrl), appCapabilities);
60+
session = Utility.CreateNewSession(CommonTestSettings.AlarmClockAppId);
6561
Assert.IsNotNull(session);
6662

6763
// Navigate to New Alarm view
@@ -80,9 +76,7 @@ public void NavigateBackModernApp()
8076
[TestMethod]
8177
public void NavigateBackSystemApp()
8278
{
83-
DesiredCapabilities appCapabilities = new DesiredCapabilities();
84-
appCapabilities.SetCapability("app", CommonTestSettings.ExplorerAppId);
85-
session = new WindowsDriver<WindowsElement>(new Uri(CommonTestSettings.WindowsApplicationDriverUrl), appCapabilities);
79+
session = Utility.CreateNewSession(CommonTestSettings.ExplorerAppId);
8680
Assert.IsNotNull(session);
8781

8882
System.Threading.Thread.Sleep(1000); // Sleep for 1 second
@@ -109,24 +103,15 @@ public void NavigateBackSystemApp()
109103
[TestMethod]
110104
public void ErrorNavigateBackNoSuchWindow()
111105
{
112-
DesiredCapabilities appCapabilities = new DesiredCapabilities();
113-
appCapabilities.SetCapability("app", CommonTestSettings.AlarmClockAppId);
114-
session = new WindowsDriver<WindowsElement>(new Uri(CommonTestSettings.WindowsApplicationDriverUrl), appCapabilities);
115-
Assert.IsNotNull(session);
116-
117106
try
118107
{
119-
session.Close();
120-
session.Navigate().Back();
108+
Utility.GetOrphanedSession().Navigate().Back();
121109
Assert.Fail("Exception should have been thrown");
122110
}
123111
catch (System.InvalidOperationException exception)
124112
{
125-
Assert.AreEqual("Currently selected window has been closed", exception.Message);
113+
Assert.AreEqual(ErrorStrings.NoSuchWindow, exception.Message);
126114
}
127-
128-
session.Quit();
129-
session = null;
130115
}
131116
}
132117
}

Tests/W3CWebDriver/Element.cs

+14
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,20 @@ public void ErrorFindElementByUnsupportedLocatorPartialLinkText()
146146
Assert.Fail("Exception should have been thrown");
147147
}
148148

149+
[TestMethod]
150+
public void ErrorFindElementNoSuchWindow()
151+
{
152+
try
153+
{
154+
WindowsElement element = Utility.GetOrphanedSession().FindElementByAccessibilityId("An accessibility id") as WindowsElement;
155+
Assert.Fail("Exception should have been thrown");
156+
}
157+
catch (System.InvalidOperationException exception)
158+
{
159+
Assert.AreEqual(ErrorStrings.NoSuchWindow, exception.Message);
160+
}
161+
}
162+
149163
[TestMethod]
150164
public void FindElementByTagName()
151165
{

0 commit comments

Comments
 (0)