Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Controls/src/Core/Page/Page.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ public Task<string> DisplayActionSheet(string title, string cancel, string destr
/// Displays a platform action sheet, allowing the application user to choose from several buttons.
/// </summary>
/// <param name="title">Title of the displayed action sheet. Can be <see langword="null"/> to hide the title.</param>
/// <param name="cancel">Text to be displayed in the 'Cancel' button. Can be null to hide the <see langword="null"/> action.</param>
/// <param name="cancel">Text to be displayed in the 'Cancel' button. Can be null to hide the cancel action.</param>
/// <param name="destruction">Text to be displayed in the 'Destruct' button. Can be <see langword="null"/> to hide the destructive option.</param>
/// <param name="flowDirection">The flow direction to be used by the action sheet.</param>
/// <param name="buttons">Text labels for additional buttons.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,15 @@ static void PresentPopUp(Page sender, Window virtualView, UIWindow platformView,
presentingWindow = senderPageWindow;
}

if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad && arguments != null)
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad &&
arguments is not null &&
alert.PopoverPresentationController is not null &&
platformView.RootViewController?.View is not null)
Comment on lines -190 to +193
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically the fix; the rest of the changes are all UI tests.

{
var topViewController = GetTopUIViewController(presentingWindow);
UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications();
var observer = NSNotificationCenter.DefaultCenter.AddObserver(UIDevice.OrientationDidChangeNotification,
n => { alert.PopoverPresentationController.SourceRect = topViewController.View.Bounds; });
n => alert.PopoverPresentationController.SourceRect = topViewController.View.Bounds);

arguments.Result.Task.ContinueWith(t =>
{
Expand All @@ -216,7 +219,7 @@ static void PresentPopUp(Page sender, Window virtualView, UIWindow platformView,
static UIViewController GetTopUIViewController(UIWindow platformWindow)
{
var topUIViewController = platformWindow.RootViewController;
while (topUIViewController.PresentedViewController is not null)
while (topUIViewController?.PresentedViewController is not null)
{
topUIViewController = topUIViewController.PresentedViewController;
}
Expand Down
10 changes: 10 additions & 0 deletions src/Controls/tests/CustomAttributes/Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,16 @@ public enum InputTransparency
CascadeTransLayoutOverlayWithButton,
}

public enum Alerts
{
AlertCancel,
AlertAcceptCancelClickAccept,
AlertAcceptCancelClickCancel,
ActionSheetClickItem,
ActionSheetClickCancel,
ActionSheetClickDestroy,
}

public static class InputTransparencyMatrix
{
// this is both for color diff and cols
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using NUnit.Framework;
using NUnit.Framework.Legacy;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests
{
public class AlertsGalleryTests : CoreGalleryBasePageTest
{
public AlertsGalleryTests(TestDevice device)
: base(device)
{
}

protected override void NavigateToGallery()
{
App.NavigateToGallery("Alerts Gallery");
}

// TODO: UI testing alert code is not yet implemented on Windows.
#if !WINDOWS
[Test]
public void AlertCancel()
{
var test = Test.Alerts.AlertCancel;

var remote = new EventViewContainerRemote(UITestContext, test);
remote.GoTo(test.ToString());

var textBeforeClick = remote.GetEventLabel().GetText();
ClassicAssert.AreEqual($"Event: {test} (none)", textBeforeClick);

remote.TapView();

var alert = App.WaitForElement(() => App.GetAlert());
ClassicAssert.NotNull(alert);

var alertText = alert.GetAlertText();
CollectionAssert.Contains(alertText, "Alert Title Here");
CollectionAssert.Contains(alertText, "Alert Message Here");

var buttons = alert.GetAlertButtons();
CollectionAssert.IsNotEmpty(buttons);
ClassicAssert.True(buttons.Count == 1, $"Expected 1 buttonText, found {buttons.Count}.");

var cancel = buttons.First();
ClassicAssert.AreEqual("CANCEL", cancel.GetText());

cancel.Click();

App.WaitForNoElement(() => App.GetAlert());

var textAfterClick = remote.GetEventLabel().GetText();
ClassicAssert.AreEqual($"Event: {test} (SUCCESS 1)", textAfterClick);
}

[Test]
[TestCase(Test.Alerts.AlertAcceptCancelClickAccept, "ACCEPT")]
[TestCase(Test.Alerts.AlertAcceptCancelClickCancel, "CANCEL")]
public void AlertAcceptCancel(Test.Alerts test, string buttonText)
{
var remote = new EventViewContainerRemote(UITestContext, test);
remote.GoTo(test.ToString());

var textBeforeClick = remote.GetEventLabel().GetText();
ClassicAssert.AreEqual($"Event: {test} (none)", textBeforeClick);

remote.TapView();

var alert = App.WaitForElement(() => App.GetAlert());
ClassicAssert.NotNull(alert);

var alertText = alert.GetAlertText();
CollectionAssert.Contains(alertText, "Alert Title Here");
CollectionAssert.Contains(alertText, "Alert Message Here");

var buttons = alert.GetAlertButtons()
.Select(b => (Element: b, Text: b.GetText()))
.ToList();
CollectionAssert.IsNotEmpty(buttons);
ClassicAssert.True(buttons.Count == 2, $"Expected 2 buttons, found {buttons.Count}.");
CollectionAssert.Contains(buttons.Select(b => b.Text), "ACCEPT");
CollectionAssert.Contains(buttons.Select(b => b.Text), "CANCEL");

var button = buttons.Single(b => b.Text == buttonText);
button.Element.Click();

App.WaitForNoElement(() => App.GetAlert());

var textAfterClick = remote.GetEventLabel().GetText();
ClassicAssert.AreEqual($"Event: {test} (SUCCESS 1)", textAfterClick);
}

[Test]
[TestCase(Test.Alerts.ActionSheetClickItem, "ITEM 2")]
[TestCase(Test.Alerts.ActionSheetClickCancel, "CANCEL")]
[TestCase(Test.Alerts.ActionSheetClickDestroy, "DESTROY")]
public void ActionSheetClickItem(Test.Alerts test, string itemText)
{
var remote = new EventViewContainerRemote(UITestContext, test);
remote.GoTo(test.ToString());

var textBeforeClick = remote.GetEventLabel().GetText();
ClassicAssert.AreEqual($"Event: {test} (none)", textBeforeClick);

remote.TapView();

var alert = App.WaitForElement(() => App.GetAlert());
ClassicAssert.NotNull(alert);

var alertText = alert.GetAlertText();
CollectionAssert.Contains(alertText, "Action Sheet Title Here");

var buttons = alert.GetAlertButtons()
.Select(b => (Element: b, Text: b.GetText()))
.ToList();
CollectionAssert.IsNotEmpty(buttons);
ClassicAssert.True(buttons.Count >= 4 && buttons.Count <= 5, $"Expected 4 or 5 buttons, found {buttons.Count}.");
CollectionAssert.Contains(buttons.Select(b => b.Text), "DESTROY");
CollectionAssert.Contains(buttons.Select(b => b.Text), "ITEM 1");
CollectionAssert.Contains(buttons.Select(b => b.Text), "ITEM 2");
CollectionAssert.Contains(buttons.Select(b => b.Text), "ITEM 3");

// handle the case where the dismiss button is an actual button
if (buttons.Count == 5)
CollectionAssert.Contains(buttons.Select(b => b.Text), "CANCEL");

if (buttons.Count == 4 && itemText == "CANCEL")
{
// handle the case where the dismiss button is a "click outside the popup"

alert.DismissAlert();
}
else
{
// handle the case where the dismiss button is an actual button

var button = buttons.Single(b => b.Text == itemText);
button.Element.Click();
}

App.WaitForNoElement(() => App.GetAlert());

var textAfterClick = remote.GetEventLabel().GetText();
ClassicAssert.AreEqual($"Event: {test} (SUCCESS 1)", textAfterClick);
}
#endif
}
}
96 changes: 96 additions & 0 deletions src/Controls/tests/TestCases/Concepts/AlertsGalleryPage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System;
using System.Threading.Tasks;
using Microsoft.Maui.Controls;

namespace Maui.Controls.Sample
{
internal class AlertsGalleryPage : CoreGalleryBasePage
{
protected override void Build()
{
// ALERTS

// Test with a single button alert that can be dismissed by tapping the button
Add(Test.Alerts.AlertCancel, async t =>
{
await DisplayAlert(
"Alert Title Here",
"Alert Message Here",
"CANCEL");
t.ReportSuccessEvent();
});

// Test alert with options to Accept or Cancel, Accept is the correct option
Add(Test.Alerts.AlertAcceptCancelClickAccept, async t =>
{
var result = await DisplayAlert(
"Alert Title Here",
"Alert Message Here",
"ACCEPT", "CANCEL");
if (result)
t.ReportSuccessEvent();
else
t.ReportFailEvent();
});

// Test alert with options to Accept or Cancel, Cancel is the correct option
Add(Test.Alerts.AlertAcceptCancelClickCancel, async t =>
{
var result = await DisplayAlert(
"Alert Title Here",
"Alert Message Here",
"ACCEPT", "CANCEL");
if (result)
t.ReportFailEvent();
else
t.ReportSuccessEvent();
});

// ACTION SHEETS

// Test action sheet with items and Cancel, Item 2 is the correct option
Add(Test.Alerts.ActionSheetClickItem, async t =>
{
var result = await DisplayActionSheet(
"Action Sheet Title Here",
"CANCEL", "DESTROY",
"ITEM 1", "ITEM 2", "ITEM 3");
if (result == "ITEM 2")
t.ReportSuccessEvent();
else
t.ReportFailEvent();
});

// Test action sheet with items and Cancel, Cancel is the correct option
Add(Test.Alerts.ActionSheetClickCancel, async t =>
{
var result = await DisplayActionSheet(
"Action Sheet Title Here",
"CANCEL", "DESTROY",
"ITEM 1", "ITEM 2", "ITEM 3");
if (result == "CANCEL")
t.ReportSuccessEvent();
else
t.ReportFailEvent();
});

// Test action sheet with items and Cancel, Destroy is the correct option
Add(Test.Alerts.ActionSheetClickDestroy, async t =>
{
var result = await DisplayActionSheet(
"Action Sheet Title Here",
"CANCEL", "DESTROY",
"ITEM 1", "ITEM 2", "ITEM 3");
if (result == "DESTROY")
t.ReportSuccessEvent();
else
t.ReportFailEvent();
});
}

ExpectedEventViewContainer<Button>
Add(Test.Alerts test, Func<ExpectedEventViewContainer<Button>, Task> action) =>
Add(new ExpectedEventViewContainer<Button>(test, new Button { Text = "Click Me!" }))
.With(t => t.View.Clicked += (_, _) => action(t));
}
}
1 change: 1 addition & 0 deletions src/Controls/tests/TestCases/CoreViews/CorePageView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public override string ToString()
new GalleryPageFactory(() => new GestureRecognizerGallery(), "Gesture Recognizer Gallery"),
new GalleryPageFactory(() => new InputTransparencyGalleryPage(), "Input Transparency Gallery"),
new GalleryPageFactory(() => new ImageLoadingGalleryPage(), "Image Loading Gallery"),
new GalleryPageFactory(() => new AlertsGalleryPage(), "Alerts Gallery"),
// Elements
new GalleryPageFactory(() => new ActivityIndicatorCoreGalleryPage(), "ActivityIndicator Gallery"),
new GalleryPageFactory(() => new BoxViewCoreGalleryPage(), "Box Gallery"),
Expand Down
Loading