summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla33612.cs
blob: 3cee8a39e420fca3fb102a1edf616afebab7be39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using System;
using System.Linq;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

#if UITEST
using NUnit.Framework;
using Xamarin.UITest;
#endif

namespace Xamarin.Forms.Controls
{
	[Preserve (AllMembers = true)]
	[Issue (IssueTracker.Bugzilla, 33612,
		"(A) Removing a page from the navigation stack causes an 'Object reference' exception in Android only",
		PlatformAffected.Android)]
	public class Bugzilla33612 : TestNavigationPage
	{
		class Page1 : ContentPage
		{
			public Page1()
			{
				var button = new Button { Text = "Go To Page 2" };
				button.Clicked += (sender, args) => Navigation.PushAsync(new Page2());

				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "This is Page 1 - the root page" },
						button
					}
				};
			}
		}

		class FakePage : ContentPage
		{
			public FakePage()
			{
				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "This is a fake page. It will never show up." }
					}
				};
			}
		}

		class Page2 : ContentPage
		{
			public Page2()
			{
				var button = new Button { Text = "Go to Page 3" };
				button.Clicked += async (sender, args) =>
				{
					int numPagesToRemove = Navigation.NavigationStack.Count;

					Page3 page3 = new Page3();
					await Navigation.PushAsync(page3);

					var fake = new FakePage();
					Navigation.InsertPageBefore(fake, page3);

					// Remove all the previous pages on the stack (i.e., Page 1)
					// This should work fine
					for (int i = 0; i < numPagesToRemove; i++)
					{
						Page p = Navigation.NavigationStack.ElementAt(0);
						Navigation.RemovePage(p);
					}
				};

				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "This is Page 2" },
						button
					}
				};
			}
		}

		class SuccessPage : ContentPage
		{
			public SuccessPage()
			{
				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "If you're seeing this, nothing crashed. Yay!" }
					}
				};
			}
		}

		class Page3 : ContentPage
		{
			public Page3()
			{
				var button = new Button { AutomationId = "btn", Text = "Return To Page 2" };
				button.Clicked += (sender, args) =>
				{
					int numPagesToRemove = Navigation.NavigationStack.Count;

					// Remove all the previous pages on the stack 
					// Originally this would fail (and crash the app), because FakePage 
					// was never actually run through SwitchContentAsync
					// which means that it never had its renderer set.
					// But now it should work just fine
					for (int i = 0; i < numPagesToRemove - 1; i++)
					{
						Page p = Navigation.NavigationStack.ElementAt(0);
						Navigation.RemovePage(p);
					}

					var success = new SuccessPage();
					Navigation.PushAsync(success);
				};

				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "This is Page 3" },
						button
					}
				};
			}
		}

		protected override void Init ()
		{
			var page1 = new Page1 ();

			PushAsync (page1);
		}

#if UITEST
		[Test]
		[UiTest (typeof(NavigationPage))]
		public void Issue33612RemovePagesWithoutRenderers ()
		{
			RunningApp.WaitForElement (q => q.Marked ("Go To Page 2"));
			RunningApp.Tap (q => q.Marked("Go To Page 2"));

			RunningApp.WaitForElement (q => q.Marked("This is Page 2"));
			RunningApp.Screenshot ("At Page 2"); 
			RunningApp.Tap (q => q.Marked("Go to Page 3"));

			RunningApp.WaitForElement ("This is Page 3");
			RunningApp.WaitForElement (q => q.Marked ("Return To Page 2"),
				timeout: TimeSpan.FromSeconds (15));
			RunningApp.Screenshot("At Page 3");
			RunningApp.Tap (q => q.Marked("Return To Page 2"));

			RunningApp.WaitForElement ("If you're seeing this, nothing crashed. Yay!");
			RunningApp.Screenshot ("Success Page");
		}
#endif
	}
}