diff --git a/demo/ShopDesk.Core/AppText.cs b/demo/ShopDesk.Core/AppText.cs index bce00f7..151b454 100644 --- a/demo/ShopDesk.Core/AppText.cs +++ b/demo/ShopDesk.Core/AppText.cs @@ -26,5 +26,7 @@ public static class AppText public static string Total(decimal amount) => "Total: " + Money.Format(amount); + public static string Exported(string path) => $"Cart exported to {path}"; + public static string OrderPlaced(OrderResult order) => $"Order {order.OrderId} placed. Total: {Money.Format(order.Total)}"; } diff --git a/demo/ShopDesk.WinForms/MainForm.cs b/demo/ShopDesk.WinForms/MainForm.cs index 03a98d3..dc98239 100644 --- a/demo/ShopDesk.WinForms/MainForm.cs +++ b/demo/ShopDesk.WinForms/MainForm.cs @@ -156,7 +156,7 @@ private void Export() if (dialog.ShowDialog(this) == DialogResult.OK) { File.WriteAllText(dialog.FileName, Services.Cart.ToCsv()); - status.Text = "Cart exported"; + status.Text = AppText.Exported(dialog.FileName); } } diff --git a/demo/ShopDesk.Wpf/MainWindow.xaml.cs b/demo/ShopDesk.Wpf/MainWindow.xaml.cs index adaa060..d675f05 100644 --- a/demo/ShopDesk.Wpf/MainWindow.xaml.cs +++ b/demo/ShopDesk.Wpf/MainWindow.xaml.cs @@ -94,7 +94,7 @@ private void OnExport(object sender, RoutedEventArgs e) if (dialog.ShowDialog(this) == true) { File.WriteAllText(dialog.FileName, Services.Cart.ToCsv()); - StatusText.Text = "Cart exported"; + StatusText.Text = AppText.Exported(dialog.FileName); } } diff --git a/docs/windows-and-locators.md b/docs/windows-and-locators.md index 1fe7cee..136991e 100644 --- a/docs/windows-and-locators.md +++ b/docs/windows-and-locators.md @@ -95,6 +95,7 @@ there are no stale references. Every action is a report step. |---|---| | `Click()`, `DoubleClick()`, `RightClick()` | `Ui:ClickMode`: `Auto` (Invoke for WPF/XAML, mouse for WinForms/Win32), `Invoke`, `Mouse` | | `Type(text)`, `Clear()` | through UI Automation when the field accepts it, otherwise typed. Password fields are masked in the report. | +| `TypeKeys(text)` | always typed on the keyboard, for controls that ignore values set through UI Automation (file dialogs) | | `Check()`, `Uncheck()`, `SetChecked(bool)` | toggle pattern; only toggles when needed | | `Select(item)` / `Select()` | an item of a combo box or list (expands and collapses as needed) / this element itself | | `OpenMenu("File", "Export cart...")` | menu bars, including WinForms drop-downs that open as separate popup windows | diff --git a/examples/Taf.Desktop.Examples/Tests/MenuAndDialogTests.cs b/examples/Taf.Desktop.Examples/Tests/MenuAndDialogTests.cs index 57924bd..052adf7 100644 --- a/examples/Taf.Desktop.Examples/Tests/MenuAndDialogTests.cs +++ b/examples/Taf.Desktop.Examples/Tests/MenuAndDialogTests.cs @@ -46,7 +46,7 @@ public void ExportWritesTheCartAsCsv() var main = On(); main.StartExport(); On().Choose(file); - main.WaitStatus("Cart exported"); + Verify.Equal(main.WaitStatus("Cart exported"), $"Cart exported to {file}", "Status bar"); File.ReadAllLines(file).Should().Equal("Product,Quantity,Amount", "Canvas Backpack,2,59.98"); } diff --git a/examples/Taf.Desktop.Examples/Windows/MainWindow.cs b/examples/Taf.Desktop.Examples/Windows/MainWindow.cs index f33578a..aa6e244 100644 --- a/examples/Taf.Desktop.Examples/Windows/MainWindow.cs +++ b/examples/Taf.Desktop.Examples/Windows/MainWindow.cs @@ -65,11 +65,11 @@ public MainWindow StartSearch(string text) return this; } - /// Waits until the status bar shows (the app finished an action). - public MainWindow WaitStatus(string text) + /// Waits until the status bar starts with (the app finished an action). + public string WaitStatus(string prefix) { - status.WaitText(text); - return this; + status.WaitUntil(s => s.Text.StartsWith(prefix, StringComparison.Ordinal), $"starts with '{prefix}'"); + return Status; } public MainWindow WaitUntilLoaded() diff --git a/src/Taf.Desktop.Core/Ui/Dialogs.cs b/src/Taf.Desktop.Core/Ui/Dialogs.cs index 3eb05ae..451ce4c 100644 --- a/src/Taf.Desktop.Core/Ui/Dialogs.cs +++ b/src/Taf.Desktop.Core/Ui/Dialogs.cs @@ -48,7 +48,8 @@ public void Choose(string path) => Step.Run($"Choose '{path}' in {Name} ('{Title { fileName = Element("fileName", Locator.ById("1148", ControlType.Edit)); // open dialog } - fileName.Type(path); + // Typed, not set: the dialog keeps its own file name and may ignore text set through UI Automation. + fileName.TypeKeys(path); fileName.Press(VirtualKeyShort.ENTER); WaitClosed(); }); diff --git a/src/Taf.Desktop.Core/Ui/UiElement.cs b/src/Taf.Desktop.Core/Ui/UiElement.cs index ee7dcaf..5744867 100644 --- a/src/Taf.Desktop.Core/Ui/UiElement.cs +++ b/src/Taf.Desktop.Core/Ui/UiElement.cs @@ -133,6 +133,12 @@ private static bool TrySetValue(IUiNode node, string text) } } + /// + /// Replaces the content by typing on the keyboard, like a user. For controls that ignore values set through UI + /// Automation (the file name box of Windows file dialogs). + /// + public void TypeKeys(string text) => Step.Run($"Type '{text}' into {Name} (keyboard)", () => WaitEnabled().TypeText(text)); + public void Clear() => Step.Run($"Clear {Name}", () => { var node = WaitEnabled();