From c0528c23135dcab98a6d3a366b5ad0b92de44476 Mon Sep 17 00:00:00 2001 From: FjFFj Date: Tue, 7 Apr 2015 06:10:13 +0200 Subject: [PATCH 1/3] Within a VisualStudio addin/package, scrolling did not work (because LargeChangeButtons are missing). Fix: ScreenItem.MakeVisible and TableVerticalScrollBar now use mouse wheel for scrolling. --- src/TestStack.White/InputDevices/Mouse.cs | 12 ++++ .../UIItems/Scrolling/ScreenItem.cs | 69 +++++++++++-------- .../TableItems/TableVerticalScrollBar.cs | 4 +- src/TestStack.White/UIItems/UIItem.cs | 9 +++ .../WindowsAPI/WindowPlacement.cs | 10 +++ 5 files changed, 73 insertions(+), 31 deletions(-) diff --git a/src/TestStack.White/InputDevices/Mouse.cs b/src/TestStack.White/InputDevices/Mouse.cs index 23e650a4..9271a1db 100644 --- a/src/TestStack.White/InputDevices/Mouse.cs +++ b/src/TestStack.White/InputDevices/Mouse.cs @@ -139,6 +139,11 @@ public virtual void DoubleClick(Point point, ActionListener actionListener) ActionPerformed(actionListener); } + public virtual void Wheel(int delta) + { + SendInput(InputFactory.Mouse(new MouseInput(120 * delta, WindowsConstants.MOUSEEVENTF_WHEEL, GetMessageExtraInfo()))); + } + private static void SendInput(Input input) { // Added check for 32/64 bit @@ -185,6 +190,13 @@ public virtual void Click(Point point, ActionListener actionListener) ActionPerformed(actionListener); } + public virtual void Wheel(Point point, int delta, ActionListener actionListener) + { + Location = point; + Wheel(delta); + ActionPerformed(actionListener); + } + private static void ActionPerformed(ActionListener actionListener) { actionListener.ActionPerformed(new Action(ActionType.WindowMessage)); diff --git a/src/TestStack.White/UIItems/Scrolling/ScreenItem.cs b/src/TestStack.White/UIItems/Scrolling/ScreenItem.cs index b8d40fe1..6e87145e 100644 --- a/src/TestStack.White/UIItems/Scrolling/ScreenItem.cs +++ b/src/TestStack.White/UIItems/Scrolling/ScreenItem.cs @@ -1,4 +1,5 @@ using System; +using System.Windows.Automation; using Castle.Core.Logging; using TestStack.White.Configuration; using TestStack.White.Utility; @@ -21,47 +22,57 @@ public ScreenItem(UIItem uiItem, IScrollBars scrollBars) internal virtual void MakeVisible(VerticalSpanProvider verticalSpanProvider) { - if (verticalScroll == null) - return; - if (!verticalScroll.IsScrollable) - return; - VerticalSpan verticalSpan = verticalSpanProvider.VerticalSpan; - if (verticalSpan.Contains(uiItem.Bounds)) { + if (verticalSpan.Contains(uiItem.Bounds)) + { logger.DebugFormat("UIItem ({0}) whose bounds are ({1}) is within bounds of parent whose vertical span is {2}", uiItem, uiItem.Bounds, verticalSpan); return; } - if (verticalScroll.IsNotMinimum) + if (verticalSpanProvider is UIItem) { - verticalScroll.SetToMinimum(); - verticalSpan = verticalSpanProvider.VerticalSpan; - logger.DebugFormat("Scroll Position set to minimum value."); - } + var containerUiItem = (UIItem)verticalSpanProvider; - if (verticalSpan.Contains(uiItem.Bounds)) - { - logger.DebugFormat("UIItem ({0}) whose bounds are ({1}) is within bounds of parent whose vertical span is {2}", uiItem, - uiItem.Bounds, verticalSpan); - return; - } + logger.DebugFormat("Trying to make visible {0}, item's bounds are {1} and parent's span is {2}", uiItem, uiItem.Bounds, verticalSpan); - logger.DebugFormat("Trying to make visible {0}, item's bounds are {1} and parent's span is {2}", uiItem, uiItem.Bounds, verticalSpan); + var success = Retry.For( + () => + { + if (uiItem.Bounds.Top + uiItem.Bounds.Bottom < verticalScroll.Bounds.Top + verticalScroll.Bounds.Bottom) + containerUiItem.MouseWheel(1); + else + containerUiItem.MouseWheel(-1); + var bounds = uiItem.Bounds; + const string messageFormat = "Trying to make {0} visible, item's bounds are {1} and parent's span is {2}"; + logger.DebugFormat(messageFormat, uiItem, bounds, verticalSpan); + return verticalSpan.Contains(bounds); + }, CoreAppXmlConfiguration.Instance.BusyTimeout(), TimeSpan.FromMilliseconds(0)); - var success = Retry.For( - () => - { - verticalScroll.ScrollDownLarge(); - var bounds = uiItem.Bounds; - const string messageFormat = "Trying to make {0} visible, item's bounds are {1} and parent's span is {2}"; - logger.DebugFormat(messageFormat, uiItem, bounds, verticalSpan); - return verticalSpan.Contains(bounds); - }, CoreAppXmlConfiguration.Instance.BusyTimeout(), TimeSpan.FromMilliseconds(0)); + if (!success) + throw new UIActionException(string.Format("Could not make the {0} visible{1}", uiItem, Constants.BusyMessage)); + } + else if (verticalScroll != null && verticalScroll.IsScrollable) + { + logger.DebugFormat("Trying to make visible {0}, item's bounds are {1} and parent's span is {2}", uiItem, uiItem.Bounds, verticalSpan); - if (!success) - throw new UIActionException(string.Format("Could not make the {0} visible{1}", uiItem, Constants.BusyMessage)); + var success = Retry.For( + () => + { + if (uiItem.Bounds.Top + uiItem.Bounds.Bottom < verticalScroll.Bounds.Top + verticalScroll.Bounds.Bottom) + verticalScroll.ScrollUpLarge(); + else + verticalScroll.ScrollDownLarge(); + var bounds = uiItem.Bounds; + const string messageFormat = "Trying to make {0} visible, item's bounds are {1} and parent's span is {2}"; + logger.DebugFormat(messageFormat, uiItem, bounds, verticalSpan); + return verticalSpan.Contains(bounds); + }, CoreAppXmlConfiguration.Instance.BusyTimeout(), TimeSpan.FromMilliseconds(0)); + + if (!success) + throw new UIActionException(string.Format("Could not make the {0} visible{1}", uiItem, Constants.BusyMessage)); + } } } } \ No newline at end of file diff --git a/src/TestStack.White/UIItems/TableItems/TableVerticalScrollBar.cs b/src/TestStack.White/UIItems/TableItems/TableVerticalScrollBar.cs index 64fa57f2..ae62962e 100644 --- a/src/TestStack.White/UIItems/TableItems/TableVerticalScrollBar.cs +++ b/src/TestStack.White/UIItems/TableItems/TableVerticalScrollBar.cs @@ -19,12 +19,12 @@ public TableVerticalScrollBar(AutomationElement automationElement, ActionListene public virtual void ScrollUp() { - mouse.Click(Bounds.ImmediateInteriorNorth(), actionListener); + mouse.Wheel(Bounds.Center(), 1, actionListener); } public virtual void ScrollDown() { - mouse.Click(Bounds.ImmediateInteriorSouth(), actionListener); + mouse.Wheel(Bounds.Center(), -1, actionListener); } public virtual void ScrollUpLarge() diff --git a/src/TestStack.White/UIItems/UIItem.cs b/src/TestStack.White/UIItems/UIItem.cs index 5f589131..c13feeb1 100644 --- a/src/TestStack.White/UIItems/UIItem.cs +++ b/src/TestStack.White/UIItems/UIItem.cs @@ -274,6 +274,15 @@ public virtual void DoubleClick() PerformIfValid(() => mouse.DoubleClick(Bounds.Center(), actionListener)); } + /// + /// Performs mouse wheel at the center of this item + /// + public virtual void MouseWheel(int delta) + { + actionListener.ActionPerforming(this); + PerformIfValid(() => mouse.Wheel(Bounds.Center(), delta, actionListener)); + } + /// /// Perform keyboard action on this UIItem /// diff --git a/src/TestStack.White/WindowsAPI/WindowPlacement.cs b/src/TestStack.White/WindowsAPI/WindowPlacement.cs index 8ead5410..15051af1 100644 --- a/src/TestStack.White/WindowsAPI/WindowPlacement.cs +++ b/src/TestStack.White/WindowsAPI/WindowPlacement.cs @@ -49,6 +49,16 @@ public struct MouseInput private readonly int time; private readonly IntPtr dwExtraInfo; + public MouseInput(int mouseData, int dwFlags, IntPtr dwExtraInfo) + { + this.dwFlags = dwFlags; + this.dwExtraInfo = dwExtraInfo; + dx = 0; + dy = 0; + time = 0; + this.mouseData = mouseData; + } + public MouseInput(int dwFlags, IntPtr dwExtraInfo) { this.dwFlags = dwFlags; From e88de4ce4969b3af5d01fd1e3fb4db27354075ec Mon Sep 17 00:00:00 2001 From: FjFFj Date: Tue, 7 Apr 2015 11:35:10 +0200 Subject: [PATCH 2/3] Fix: previous change broke WPF ComboBox scrolling --- .../UIItems/Scrolling/ScreenItem.cs | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/TestStack.White/UIItems/Scrolling/ScreenItem.cs b/src/TestStack.White/UIItems/Scrolling/ScreenItem.cs index 6e87145e..0ad9e827 100644 --- a/src/TestStack.White/UIItems/Scrolling/ScreenItem.cs +++ b/src/TestStack.White/UIItems/Scrolling/ScreenItem.cs @@ -31,19 +31,28 @@ internal virtual void MakeVisible(VerticalSpanProvider verticalSpanProvider) return; } - if (verticalSpanProvider is UIItem) + if (verticalScroll != null && verticalScroll.IsScrollable) { - var containerUiItem = (UIItem)verticalSpanProvider; - logger.DebugFormat("Trying to make visible {0}, item's bounds are {1} and parent's span is {2}", uiItem, uiItem.Bounds, verticalSpan); + if (verticalScroll.IsNotMinimum) + { + verticalScroll.SetToMinimum(); + verticalSpan = verticalSpanProvider.VerticalSpan; + logger.DebugFormat("Scroll Position set to minimum value."); + } + + if (verticalSpan.Contains(uiItem.Bounds)) + { + logger.DebugFormat("UIItem ({0}) whose bounds are ({1}) is within bounds of parent whose vertical span is {2}", uiItem, + uiItem.Bounds, verticalSpan); + return; + } + var success = Retry.For( () => { - if (uiItem.Bounds.Top + uiItem.Bounds.Bottom < verticalScroll.Bounds.Top + verticalScroll.Bounds.Bottom) - containerUiItem.MouseWheel(1); - else - containerUiItem.MouseWheel(-1); + verticalScroll.ScrollDownLarge(); var bounds = uiItem.Bounds; const string messageFormat = "Trying to make {0} visible, item's bounds are {1} and parent's span is {2}"; logger.DebugFormat(messageFormat, uiItem, bounds, verticalSpan); @@ -53,17 +62,19 @@ internal virtual void MakeVisible(VerticalSpanProvider verticalSpanProvider) if (!success) throw new UIActionException(string.Format("Could not make the {0} visible{1}", uiItem, Constants.BusyMessage)); } - else if (verticalScroll != null && verticalScroll.IsScrollable) + else if (verticalSpanProvider is UIItem) { + var containerUiItem = (UIItem)verticalSpanProvider; + logger.DebugFormat("Trying to make visible {0}, item's bounds are {1} and parent's span is {2}", uiItem, uiItem.Bounds, verticalSpan); var success = Retry.For( () => { if (uiItem.Bounds.Top + uiItem.Bounds.Bottom < verticalScroll.Bounds.Top + verticalScroll.Bounds.Bottom) - verticalScroll.ScrollUpLarge(); + containerUiItem.MouseWheel(1); else - verticalScroll.ScrollDownLarge(); + containerUiItem.MouseWheel(-1); var bounds = uiItem.Bounds; const string messageFormat = "Trying to make {0} visible, item's bounds are {1} and parent's span is {2}"; logger.DebugFormat(messageFormat, uiItem, bounds, verticalSpan); From dbdefb61fdf25eb003b97bec9b186a35b645d518 Mon Sep 17 00:00:00 2001 From: FjFFj Date: Tue, 7 Apr 2015 11:36:57 +0200 Subject: [PATCH 3/3] Improved UITests: runs now also with shadow copying enabled. Support for non-english OS --- .../Infrastructure/WindowsConfiguration.cs | 7 +- .../Scenarios/Win32Tests.cs | 78 +++++++++++++++---- src/TestStack.White.UITests/WhiteTestBase.cs | 4 + 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/src/TestStack.White.UITests/Infrastructure/WindowsConfiguration.cs b/src/TestStack.White.UITests/Infrastructure/WindowsConfiguration.cs index 89dea91a..b39cada3 100644 --- a/src/TestStack.White.UITests/Infrastructure/WindowsConfiguration.cs +++ b/src/TestStack.White.UITests/Infrastructure/WindowsConfiguration.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.IO; using System.Reflection; using TestStack.White.Factory; @@ -21,7 +22,9 @@ protected WindowsConfiguration(WindowsFramework framework) public override Application LaunchApplication() { - var app = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), ApplicationExePath()); + // use Codebase so that the tests work also with shadowing enabled + var codeBase = new Uri(Assembly.GetExecutingAssembly().CodeBase); + var app = Path.Combine(Path.GetDirectoryName(codeBase.LocalPath), ApplicationExePath()); var processStartInfo = new ProcessStartInfo { FileName = app, diff --git a/src/TestStack.White.UITests/Scenarios/Win32Tests.cs b/src/TestStack.White.UITests/Scenarios/Win32Tests.cs index fde070bd..b4ea44a7 100644 --- a/src/TestStack.White.UITests/Scenarios/Win32Tests.cs +++ b/src/TestStack.White.UITests/Scenarios/Win32Tests.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Globalization; using System.Linq; using TestStack.White.Factory; using TestStack.White.UIItems; @@ -20,14 +21,26 @@ public class Win32Tests [Fact] public void NotepadTests() { + string windowTitle = "Untitled - Notepad"; + string fontMenuItemShortcuts = "of"; + string fontDialogTitle = "Font"; + + var lang = CultureInfo.InstalledUICulture.Name; + if (lang.StartsWith("de")) + { + windowTitle = "Unbenannt - Editor"; + fontMenuItemShortcuts = "os"; + fontDialogTitle = "Schriftart"; + } + using (var app = Application.Launch(Notepad)) - using (var window = app.GetWindow("Untitled - Notepad")) + using (var window = app.GetWindow(windowTitle)) { window.Keyboard.PressSpecialKey(KeyboardInput.SpecialKeys.ALT); - window.Keyboard.Enter("o"); - window.Keyboard.Enter("f"); + foreach (char c in fontMenuItemShortcuts) + window.Keyboard.Enter(c.ToString()); - using (var modalWindow = window.ModalWindow("Font")) + using (var modalWindow = window.ModalWindow(fontDialogTitle)) { Assert.NotNull(modalWindow); } @@ -37,15 +50,27 @@ public void NotepadTests() [Fact] public void InternetExplorerTests() { + string toolTipText = "Tools (Alt+X)"; + string optionsMenuItem = "Internet Options"; + string optionsDialogTitle = "Internet Options"; + + var lang = CultureInfo.InstalledUICulture.Name; + if (lang.StartsWith("de")) + { + toolTipText = "Extras (Alt+X)"; + optionsMenuItem = "Internetoptionen"; + optionsDialogTitle = "Internetoptionen"; + } + using (var app = Application.Launch(InternetExplorer)) using (var window = app.GetWindows().Single()) { var button = window.Get