Speed up core UI tests and reduce flakiness (#6395)

* Speed up ViewUITests and hopefully reduce flakiness

* Make focus tests work even when keyboard pops up

* Move Date/Time picker tests to the end so they can't break the other bubbling tests
Add delay before trying to dismiss dialogs so they can fully appear

* Fix accidental triggering of Picker when removing focus from Entry

* Bump up number of tests before restart
This commit is contained in:
E.Z. Hart 2019-06-04 12:28:21 -06:00 коммит произвёл Rui Marinho
Родитель ca409d3d14
Коммит 3bc2e5e94b
5 изменённых файлов: 180 добавлений и 152 удалений

Просмотреть файл

@ -73,6 +73,7 @@ namespace Xamarin.Forms.Controls.Issues
{
// These controls show a pop-up which we have to cancel/done out of before we can continue
#if __ANDROID__
System.Threading.Tasks.Task.Delay(2000).Wait(); // If we hit back before the dialog is fully up, it may not dismiss
RunningApp.Back();
#elif __IOS__
var cancelButtonText = "Done";
@ -200,9 +201,6 @@ namespace Xamarin.Forms.Controls.Issues
// We don't use 'SearchBar' here because on Android it sometimes finds the wrong control
col1.Children.Add(MenuButton("TestSearchBar", () => new SearchBar()));
col2.Children.Add(MenuButton(nameof(DatePicker), () => new DatePicker()));
col2.Children.Add(MenuButton(nameof(TimePicker), () => new TimePicker()));
var slider = new Slider();
slider.On<iOS>().SetUpdateOnTap(true);
col2.Children.Add(MenuButton(nameof(Slider), () => slider));
@ -211,6 +209,9 @@ namespace Xamarin.Forms.Controls.Issues
col2.Children.Add(MenuButton(nameof(Stepper), () => new Stepper()));
col2.Children.Add(MenuButton(nameof(BoxView), () => new BoxView { BackgroundColor = Color.DarkMagenta, WidthRequest = 100, HeightRequest = 100 }));
col2.Children.Add(MenuButton(nameof(DatePicker), () => new DatePicker()));
col2.Children.Add(MenuButton(nameof(TimePicker), () => new TimePicker()));
return new ContentPage { Content = layout };
}

Просмотреть файл

@ -250,7 +250,7 @@ namespace Xamarin.Forms.Controls
}
static int s_testsrun;
const int ConsecutiveTestLimit = 10;
const int ConsecutiveTestLimit = 20;
// Until we get more of our memory leak issues worked out, restart the app
// after a specified number of tests so we don't get bogged down in GC

Просмотреть файл

@ -1,106 +1,76 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using System.Linq;
using Xamarin.Forms.CustomAttributes;
namespace Xamarin.Forms.Controls
{
internal class CoreGalleryPage<T> : ContentPage
where T : View, new ()
where T : View, new()
{
List<View> _views;
List<ViewContainer<T>> _viewContainers;
int _currentIndex;
Picker _picker;
StackLayout _moveNextStack;
ViewContainer<T> _backgroundColorViewContainer;
ViewContainer<T> _opacityViewContainer;
ViewContainer<T> _rotationViewContainer;
ViewContainer<T> _rotationXViewContainer;
ViewContainer<T> _rotationYViewContainer;
ViewContainer<T> _scaleViewContainer;
ViewContainer<T> _translationXViewContainer;
ViewContainer<T> _translationYViewContainer;
StateViewContainer<T> _focusStateViewContainer;
StateViewContainer<T> _isFocusedStateViewContainer;
StateViewContainer<T> _isVisibleStateViewContainer;
EventViewContainer<T> _gestureRecognizerEventViewContainer;
EventViewContainer<T> _focusedEventViewContainer;
EventViewContainer<T> _unfocusedEventViewContainer;
LayeredViewContainer<T> _inputTransparentViewContainer;
Entry _targetEntry;
StackLayout _layout;
protected StateViewContainer<T> IsEnabledStateViewContainer { get; private set; }
protected StackLayout Layout { get; private set; }
internal CoreGalleryPage ()
internal CoreGalleryPage()
{
Layout = new StackLayout {
Padding = new Thickness (20)
Layout = new StackLayout
{
Padding = new Thickness(20)
};
var modalDismissButton = new Button () {
var modalDismissButton = new Button()
{
Text = "Dismiss Page",
Command = new Command (async () =>
{
if (_picker.SelectedIndex == 0)
await Navigation.PopAsync();
else
_picker.SelectedIndex--;
})
Command = new Command(async () =>
{
if (_picker.SelectedIndex == 0)
{
await Navigation.PopAsync();
}
else
{
_picker.SelectedIndex--;
}
})
};
Layout.Children.Add (modalDismissButton);
Layout.Children.Add(modalDismissButton);
Build (Layout);
Build(Layout);
Content = new ScrollView { AutomationId = "GalleryScrollView", Content = Layout };
}
protected virtual void InitializeElement (T element) {}
protected virtual void InitializeElement(T element) { }
protected virtual void Build (StackLayout stackLayout)
protected virtual void Build(StackLayout stackLayout)
{
var isFocusedView = new T ();
isFocusedView.SetValueCore (IsFocusedPropertyKey, true);
var isFocusedView = new T();
isFocusedView.SetValueCore(IsFocusedPropertyKey, true);
var viewContainers = new[] {
_isFocusedStateViewContainer = new StateViewContainer<T> (Test.VisualElement.IsFocused, isFocusedView),
_backgroundColorViewContainer = new ViewContainer<T> (Test.VisualElement.BackgroundColor, new T { BackgroundColor = Color.Blue }),
_focusStateViewContainer = new StateViewContainer<T> (Test.VisualElement.Focus, new T ()),
_gestureRecognizerEventViewContainer = new EventViewContainer<T> (Test.View.GestureRecognizers, new T ()),
_inputTransparentViewContainer = new LayeredViewContainer<T> (Test.VisualElement.InputTransparent, new T { InputTransparent = true }),
IsEnabledStateViewContainer = new StateViewContainer<T> (Test.VisualElement.IsEnabled, new T { IsEnabled = true }),
_focusedEventViewContainer = new EventViewContainer<T> (Test.VisualElement.Focused, new T ()),
_unfocusedEventViewContainer = new EventViewContainer<T> (Test.VisualElement.Unfocused, new T ()),
_isVisibleStateViewContainer = new StateViewContainer<T> (Test.VisualElement.IsVisible, new T { IsVisible = true }),
_opacityViewContainer = new ViewContainer<T> (Test.VisualElement.Opacity, new T { Opacity = 0.5 }),
_rotationViewContainer = new ViewContainer<T> (Test.VisualElement.Rotation, new T { Rotation = 10 }),
_rotationXViewContainer = new ViewContainer<T> (Test.VisualElement.RotationX, new T { RotationX = 33 }),
_rotationYViewContainer = new ViewContainer<T> (Test.VisualElement.RotationY, new T { RotationY = 10 }),
_scaleViewContainer = new ViewContainer<T> (Test.VisualElement.Scale, new T { Scale = 0.5 }),
_translationXViewContainer = new ViewContainer<T> (Test.VisualElement.TranslationX, new T { TranslationX = 30 }),
_translationYViewContainer = new ViewContainer<T> (Test.VisualElement.TranslationY, new T { TranslationY = 30 }),
};
// Set state
IsEnabledStateViewContainer.StateChangeButton.Command = new Command (() => {
IsEnabledStateViewContainer = new StateViewContainer<T>(Test.VisualElement.IsEnabled, new T { IsEnabled = true });
IsEnabledStateViewContainer.StateChangeButton.Command = new Command(() =>
{
IsEnabledStateViewContainer.View.IsEnabled = !IsEnabledStateViewContainer.View.IsEnabled;
});
_isVisibleStateViewContainer.StateChangeButton.Command = new Command (() => {
_isVisibleStateViewContainer.View.IsVisible = !_isVisibleStateViewContainer.View.IsVisible;
var isVisibleStateViewContainer = new StateViewContainer<T>(Test.VisualElement.IsVisible, new T { IsVisible = true });
isVisibleStateViewContainer.StateChangeButton.Command = new Command(() =>
{
isVisibleStateViewContainer.View.IsVisible = !isVisibleStateViewContainer.View.IsVisible;
});
var isFocusedStateViewContainer = new StateViewContainer<T>(Test.VisualElement.IsFocused, isFocusedView);
isFocusedStateViewContainer.StateChangeButton.Command = new Command(() =>
{
_isFocusedStateViewContainer.StateChangeButton.Command = new Command(() => {
if ((bool)isFocusedView.GetValue(VisualElement.IsFocusedProperty))
{
isFocusedView.SetValueCore(IsFocusedPropertyKey, false);
@ -111,81 +81,144 @@ namespace Xamarin.Forms.Controls
}
});
_focusStateViewContainer.StateChangeButton.Command = new Command (() => {
if (_focusStateViewContainer.View.IsFocused) {
_focusStateViewContainer.View.Unfocus ();
} else {
_focusStateViewContainer.View.Focus ();
var focusStateViewContainer = new StateViewContainer<T>(Test.VisualElement.Focus, new T());
focusStateViewContainer.StateChangeButton.Command = new Command(() =>
{
if (focusStateViewContainer.View.IsFocused)
{
focusStateViewContainer.View.Unfocus();
}
else
{
focusStateViewContainer.View.Focus();
}
});
_focusedEventViewContainer.View.Focused += (sender, args) => _focusedEventViewContainer.EventFired ();
_unfocusedEventViewContainer.View.Unfocused += (sender, args) => _unfocusedEventViewContainer.EventFired ();
var focusedEventViewContainer = new EventViewContainer<T>(Test.VisualElement.Focused, new T());
focusedEventViewContainer.View.Focused += (sender, args) => focusedEventViewContainer.EventFired();
_gestureRecognizerEventViewContainer.View.GestureRecognizers.Add (
new TapGestureRecognizer {
Command = new Command (() => _gestureRecognizerEventViewContainer.EventFired ())
var unfocusedEventViewContainer = new EventViewContainer<T>(Test.VisualElement.Unfocused, new T());
unfocusedEventViewContainer.View.Unfocused += (sender, args) => unfocusedEventViewContainer.EventFired();
var gestureRecognizerEventViewContainer = new EventViewContainer<T>(Test.View.GestureRecognizers, new T());
gestureRecognizerEventViewContainer.View.GestureRecognizers.Add(
new TapGestureRecognizer
{
Command = new Command(() => gestureRecognizerEventViewContainer.EventFired())
}
);
_views = new List<View> (viewContainers.Select (o => o.ContainerLayout));
_moveNextStack = new StackLayout ();
var moveNextButton = new Button ();
moveNextButton.Text = "Move Next";
moveNextButton.AutomationId = "MoveNextButton";
moveNextButton.Clicked += delegate (object sender, EventArgs e) {
if (!_views.Any ())
return;
if (_currentIndex + 1 >= _views.Count) {
return;
}
_currentIndex += 1;
_moveNextStack.Children.RemoveAt (2);
_moveNextStack.Children.Add (_views[_currentIndex]);
_picker.SelectedIndexChanged -= PickerSelectedIndexChanged;
_picker.SelectedIndex = _currentIndex;
_picker.SelectedIndexChanged += PickerSelectedIndexChanged;
_viewContainers = new List<ViewContainer<T>> {
isFocusedStateViewContainer,
new ViewContainer<T> (Test.VisualElement.BackgroundColor, new T { BackgroundColor = Color.Blue }),
focusStateViewContainer,
gestureRecognizerEventViewContainer,
new LayeredViewContainer<T> (Test.VisualElement.InputTransparent, new T { InputTransparent = true }),
IsEnabledStateViewContainer,
focusedEventViewContainer,
unfocusedEventViewContainer,
isVisibleStateViewContainer,
new ViewContainer<T> (Test.VisualElement.Opacity, new T { Opacity = 0.5 }),
new ViewContainer<T> (Test.VisualElement.Rotation, new T { Rotation = 10 }),
new ViewContainer<T> (Test.VisualElement.RotationX, new T { RotationX = 33 }),
new ViewContainer<T> (Test.VisualElement.RotationY, new T { RotationY = 10 }),
new ViewContainer<T> (Test.VisualElement.Scale, new T { Scale = 0.5 }),
new ViewContainer<T> (Test.VisualElement.TranslationX, new T { TranslationX = 30 }),
new ViewContainer<T> (Test.VisualElement.TranslationY, new T { TranslationY = 30 }),
};
_layout = new StackLayout();
_targetEntry = new Entry { AutomationId = "TargetViewContainer", Placeholder = "Jump To ViewContainer" };
var goButton = new Button
{
Text = "Go",
AutomationId = "GoButton"
};
goButton.Clicked += GoClicked;
_picker = new Picker();
foreach (var container in viewContainers) {
foreach (var container in _viewContainers)
{
_picker.Items.Add(container.TitleLabel.Text);
}
_picker.SelectedIndex = _currentIndex;
_picker.SelectedIndexChanged += PickerSelectedIndexChanged;
_moveNextStack.Children.Add (_picker);
_moveNextStack.Children.Add (moveNextButton);
_moveNextStack.Children.Add (_views[_currentIndex]);
_layout.Children.Add(_picker);
_layout.Children.Add(_targetEntry);
_layout.Children.Add(goButton);
_layout.Children.Add(_viewContainers[_currentIndex].ContainerLayout);
stackLayout.Children.Add (_moveNextStack);
stackLayout.Children.Add(_layout);
if (!SupportsFocus) {
stackLayout.Children.Remove (_focusStateViewContainer.ContainerLayout);
stackLayout.Children.Remove (_isFocusedStateViewContainer.ContainerLayout);
if (!SupportsFocus)
{
stackLayout.Children.Remove(focusStateViewContainer.ContainerLayout);
stackLayout.Children.Remove(isFocusedStateViewContainer.ContainerLayout);
}
if (!SupportsTapGestureRecognizer)
stackLayout.Children.Remove (_gestureRecognizerEventViewContainer.ContainerLayout);
{
stackLayout.Children.Remove(gestureRecognizerEventViewContainer.ContainerLayout);
}
foreach (var element in viewContainers)
InitializeElement (element.View);
foreach (var element in _viewContainers)
{
InitializeElement(element.View);
}
}
void PickerSelectedIndexChanged (object sender, EventArgs eventArgs)
void GoClicked(object sender, EventArgs e)
{
if (!_viewContainers.Any())
{
return;
}
var target = _targetEntry.Text;
_targetEntry.Text = "";
var index = -1;
if (string.IsNullOrEmpty(target))
{
return;
}
for (int n = 0; n < _viewContainers.Count; n++)
{
if (_viewContainers[n].View.AutomationId == target)
{
index = n;
break;
}
}
if (index < 0)
{
return;
}
var targetContainer = _viewContainers[index];
_layout.Children.RemoveAt(3);
_layout.Children.Add(targetContainer.ContainerLayout);
_picker.SelectedIndexChanged -= PickerSelectedIndexChanged;
_picker.SelectedIndex = index;
_picker.SelectedIndexChanged += PickerSelectedIndexChanged;
}
void PickerSelectedIndexChanged(object sender, EventArgs eventArgs)
{
_currentIndex = _picker.SelectedIndex;
_moveNextStack.Children.RemoveAt (2);
_moveNextStack.Children.Add (_views[_currentIndex]);
_layout.Children.RemoveAt(3);
_layout.Children.Add(_viewContainers[_currentIndex].ContainerLayout);
}
protected virtual bool SupportsTapGestureRecognizer
{
get { return true; }
@ -196,9 +229,10 @@ namespace Xamarin.Forms.Controls
get { return true; }
}
protected void Add (ViewContainer<T> view) {
_views.Add (view.ContainerLayout);
_picker.Items.Add(view.TitleLabel.Text);
protected void Add(ViewContainer<T> viewContainer)
{
_viewContainers.Add(viewContainer);
_picker.Items.Add(viewContainer.TitleLabel.Text);
}
}
}

Просмотреть файл

@ -73,25 +73,11 @@ namespace Xamarin.Forms.Core.UITests
Height = scrollBounds.Height,
};
}
while (true)
{
#if __MACOS__
var result = App.Query(o => o.Raw(ViewQuery));
#else
var result = App.Query (o => o.Raw(ContainerQuery));
#endif
if (result.Any())
break;
App.Tap(o => o.Raw("* marked:'MoveNextButton'"));
}
//Assert.True (App.ScrollForElement (
// ContainerQuery, new Drag (scrollBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium)
//), "Failed to find element in: " + callerMemberName);
App.Screenshot("Go to element");
App.WaitForElement("TargetViewContainer");
App.Tap("TargetViewContainer");
App.EnterText(callerMemberName.Replace("_", "") + "VisualElement");
App.Tap("GoButton");
}
public void TapView()
@ -160,7 +146,9 @@ namespace Xamarin.Forms.Core.UITests
return result;
}
#endif
App.WaitForElement(q => q.Raw(query));
bool found = MaybeGetProperty<string>(App, query, propertyPath, out prop) ||
MaybeGetProperty<float>(App, query, propertyPath, out prop) ||
MaybeGetProperty<bool>(App, query, propertyPath, out prop) ||

Просмотреть файл

@ -1,6 +1,7 @@
using NUnit.Framework;
using Xamarin.Forms.Controls.Issues;
using Xamarin.Forms.CustomAttributes;
using Xamarin.UITest.Queries;
namespace Xamarin.Forms.Core.UITests
{
@ -25,14 +26,18 @@ namespace Xamarin.Forms.Core.UITests
{
var remote = new StateViewContainerRemote(App, Test.VisualElement.Focus, PlatformViewType);
remote.GoTo();
bool isFocused = System.Convert.ToBoolean( App.Query("FocusStateLabel")[0].ReadText());
Assert.IsFalse(isFocused);
Assert.IsFalse(IsFocused());
remote.TapView();
isFocused = System.Convert.ToBoolean(App.Query("FocusStateLabel")[0].ReadText());
Assert.IsTrue(isFocused);
App.Tap("FocusStateLabel");
isFocused = System.Convert.ToBoolean(App.Query("FocusStateLabel")[0].ReadText());
Assert.IsFalse(isFocused);
Assert.IsTrue(IsFocused());
App.Tap("Go"); // Won't do anything, we just need to take focus away from the Entry
Assert.IsFalse(IsFocused());
}
bool IsFocused()
{
var focusedText = App.Query(q => q.Marked("FocusStateLabel").All())[0].ReadText();
return System.Convert.ToBoolean(focusedText);
}
[UiTestExempt(ExemptReason.CannotTest, "Invalid interaction")]