diff options
Diffstat (limited to 'main/tests/UserInterfaceTests')
30 files changed, 2655 insertions, 525 deletions
diff --git a/main/tests/UserInterfaceTests/Controllers/NewFileController.cs b/main/tests/UserInterfaceTests/Controllers/NewFileController.cs index b87fbdb0ca..b4e8879936 100644 --- a/main/tests/UserInterfaceTests/Controllers/NewFileController.cs +++ b/main/tests/UserInterfaceTests/Controllers/NewFileController.cs @@ -37,14 +37,25 @@ namespace UserInterfaceTests Action<string> takeScreenshot; + Func<AppQuery, AppQuery> categoryViewQuery = c => c.TreeView ().Marked ("catView").Model (); + Func<AppQuery, AppQuery> fileTypeQuery = c => c.TreeView ().Marked ("newFileTemplateTreeView").Model ("templateStore__Name"); + public NewFileController (Action<string> takeScreenshot = null) { - this.takeScreenshot = takeScreenshot ?? delegate { }; + this.takeScreenshot = Util.GetNonNullAction (takeScreenshot); } - public static void Create (NewFileOptions options, Action<string> takeScreenshot = null) + public static void Create (NewFileOptions options, UITestBase testContext = null) { - var ctrl = new NewFileController (takeScreenshot); + options.PrintData (); + Action<string> screenshotAction = (s) => {}; + if (testContext != null) { + testContext.ReproStep (string.Format ("Add a new file of type '{0}' named '{1}'", + options.FileType, options.FileName), options); + screenshotAction = testContext.TakeScreenShot; + } + + var ctrl = new NewFileController (screenshotAction); ctrl.Open (); ctrl.ConfigureAddToProject (!string.IsNullOrEmpty (options.AddToProjectName), options.AddToProjectName); ctrl.SelectFileTypeCategory (options.FileTypeCategory, options.FileTypeCategoryRoot); @@ -63,16 +74,18 @@ namespace UserInterfaceTests public bool SelectFileTypeCategory (string fileTypeCategory, string fileTypeCategoryRoot = "C#") { - var openChild = Session.ClickElement (c => c.TreeView ().Marked ("catView").Model ().Text (fileTypeCategoryRoot)); - var resultParent = Session.SelectElement (c => c.TreeView ().Marked ("catView").Model ().Text (fileTypeCategoryRoot).Children ().Text (fileTypeCategory)); - var result = Session.SelectElement (c => c.TreeView ().Marked ("catView").Model ().Text (fileTypeCategory)); + var openChild = Session.ClickElement (c => categoryViewQuery (c).Text (fileTypeCategoryRoot)); + var resultParent = Session.SelectElement (c => categoryViewQuery (c).Text (fileTypeCategoryRoot).Children ().Text (fileTypeCategory)); + var result = Session.SelectElement (c => categoryViewQuery (c).Text (fileTypeCategory)) && + Session.WaitForElement (c => categoryViewQuery (c).Text (fileTypeCategory).Selected ()).Length > 0; takeScreenshot ("FileTypeCategory-Selected"); return resultParent || result; } public bool SelectFileType (string fileType) { - var result = Session.SelectElement (c => c.TreeView ().Marked ("newFileTemplateTreeView").Model ("templateStore__Name").Contains (fileType)); + var result = Session.SelectElement (c => fileTypeQuery (c).Contains (fileType)) && + Session.WaitForElement (c => fileTypeQuery (c).Contains (fileType).Selected ()).Length > 0; takeScreenshot ("FileType-Selected"); return result; } diff --git a/main/tests/UserInterfaceTests/Controllers/NewProjectController.cs b/main/tests/UserInterfaceTests/Controllers/NewProjectController.cs index 1b9c517323..05719054c0 100644 --- a/main/tests/UserInterfaceTests/Controllers/NewProjectController.cs +++ b/main/tests/UserInterfaceTests/Controllers/NewProjectController.cs @@ -28,6 +28,7 @@ using MonoDevelop.Components.AutoTest; using MonoDevelop.Ide.Commands; using NUnit.Framework; using System.Threading; +using System.Linq; namespace UserInterfaceTests { @@ -37,27 +38,74 @@ namespace UserInterfaceTests get { return TestService.Session; } } - Func<AppQuery, AppQuery> previewTree = (c) => c.TreeView ().Marked ("folderTreeView").Model ("folderTreeStore__NodeName"); + Func<AppQuery, AppQuery> templateCategoriesTreeViewQuery = c => c.TreeView ().Marked ("templateCategoriesTreeView"); + Func<AppQuery, AppQuery> templatesTreeViewQuery = c => c.TreeView ().Marked ("templatesTreeView"); + + Func<AppQuery, AppQuery> previewTree = c => c.TreeView ().Marked ("folderTreeView").Model ("folderTreeStore__NodeName"); + Func<AppQuery, AppQuery> templateCategoriesQuery = c => c.TreeView ().Marked ("templateCategoriesTreeView").Model ("templateCategoriesListStore__Name"); + Func<AppQuery, AppQuery> templatesQuery = c => c.TreeView ().Marked ("templatesTreeView").Model ("templateListStore__Name"); public void Open () { Session.ExecuteCommand (FileCommands.NewProject); + WaitForOpen (); + } + + public void Open (string addToSolutionName) + { + SolutionExplorerController.SelectSolution (addToSolutionName); + Session.ExecuteCommand (ProjectCommands.AddNewProject); + WaitForOpen (); + } + + public void WaitForOpen () + { Session.WaitForElement (c => c.Window ().Marked ("MonoDevelop.Ide.Projects.GtkNewProjectDialogBackend")); } + public void Select (TemplateSelectionOptions templateOptions) + { + SelectTemplateType (templateOptions.CategoryRoot, templateOptions.Category); + SelectTemplate (templateOptions.TemplateKindRoot, templateOptions.TemplateKind); + } + + public bool IsSelected (TemplateSelectionOptions templateOptions) + { + return true; +// return Session.SelectElement (templateCategoriesTreeViewQuery) && IsTemplateTypeSelected (templateOptions.CategoryRoot, templateOptions.Category) +// && Session.SelectElement (templatesTreeViewQuery) && IsTemplateSelected (templateOptions.TemplateKindRoot, templateOptions.TemplateKind); + } + public bool SelectTemplateType (string categoryRoot, string category) { - return Session.SelectElement (c => c.TreeView ().Marked ("templateCategoriesTreeView").Model ("templateCategoriesListStore__Name").Contains (categoryRoot).NextSiblings ().Text (category)); + return Session.SelectElement (c => templateCategoriesQuery (c).Contains (categoryRoot).NextSiblings ().Text (category)) + && IsTemplateTypeSelected (categoryRoot, category); } public bool SelectTemplate (string kindRoot, string kind) { - return Session.SelectElement (c => c.TreeView ().Marked ("templatesTreeView").Model ("templateListStore__Name").Contains (kindRoot).NextSiblings ().Text (kind)); + return Session.SelectElement (c => templatesQuery (c).Contains (kindRoot).NextSiblings ().Text (kind)) + && IsTemplateSelected (kindRoot, kind); + } + + public bool IsTemplateTypeSelected (string categoryRoot, string category) + { + return Session.WaitForElement (c => templateCategoriesQuery (c).Contains (categoryRoot).NextSiblings ().Text (category).Selected ()).Any (); + } + + public bool IsTemplateSelected (string kindRoot, string kind) + { + return Session.WaitForElement (c => templatesQuery (c).Contains (kindRoot).NextSiblings ().Text (kind).Selected ()).Any (); } public bool Next () { - return Session.ClickElement (c => c.Button ().Marked ("nextButton")); + return Session.ClickElement (c => c.Button ().Text ("Next")); + } + + public bool Create () + { + return Session.ClickElement (c => c.Button ().Text ("Create")); } public bool Previous () @@ -70,14 +118,23 @@ namespace UserInterfaceTests return Session.ClickElement (c => c.Button ().Marked ("cancelButton")); } - public bool SetProjectName (string projectName) + public bool SetProjectName (string projectName, bool addToExistingSolution) { - return Session.EnterText (c => c.Textfield ().Marked ("projectNameTextBox"), projectName); + Func<AppQuery, AppQuery> projectNameTextBox = c => c.Textfield ().Marked ("projectNameTextBox"); + if (addToExistingSolution && Session.Query (c => projectNameTextBox (c).Sensitivity (false)).Length > 0) { + return Session.Query (c => projectNameTextBox (c).Text (projectName)).Length > 0; + } + return Session.EnterText (projectNameTextBox, projectName); } - public bool SetSolutionName (string solutionName) + public bool SetSolutionName (string solutionName, bool addToExistingSolution) { - return Session.EnterText (c => c.Textfield ().Marked ("solutionNameTextBox"), solutionName); + Func<AppQuery, AppQuery> solutionNameTextBox = c => c.Textfield ().Marked ("solutionNameTextBox"); + if (addToExistingSolution) { + return Session.Query (c => solutionNameTextBox (c).Sensitivity (false)).Length > 0 && + Session.Query (c => solutionNameTextBox (c).Text (solutionName)).Length > 0; + } + return Session.EnterText (solutionNameTextBox, solutionName); } public bool SetSolutionLocation (string solutionLocation) diff --git a/main/tests/UserInterfaceTests/Controllers/NuGetController.cs b/main/tests/UserInterfaceTests/Controllers/NuGetController.cs index 92cf57a4ad..3425a7b31c 100644 --- a/main/tests/UserInterfaceTests/Controllers/NuGetController.cs +++ b/main/tests/UserInterfaceTests/Controllers/NuGetController.cs @@ -25,21 +25,11 @@ // THE SOFTWARE. using System; using MonoDevelop.Components.AutoTest; -using UserInterfaceTests; using MonoDevelop.Components.Commands; using NUnit.Framework; namespace UserInterfaceTests { - public class NuGetPackageOptions - { - public string PackageName { get; set;} - - public string Version { get; set;} - - public bool IsPreRelease { get; set;} - } - public class NuGetController { static AutoTestClientSession Session { @@ -48,31 +38,76 @@ namespace UserInterfaceTests Action<string> takeScreenshot; - readonly Func<AppQuery,AppQuery> nugetWindow; + bool isUpdate; + + static readonly Func<AppQuery,AppQuery> nugetWindow = c => c.Window ().Marked ("Add Packages"); readonly Func<AppQuery,AppQuery> addPackageButton; + readonly Func<AppQuery,AppQuery> updatePackageButton; readonly Func<AppQuery,AppQuery> resultList; readonly Func<AppQuery,AppQuery> includePreRelease; - public static void AddPackage (NuGetPackageOptions packageOptions, Action<string> takeScreenshot = null) + public static void AddPackage (NuGetPackageOptions packageOptions, UITestBase testContext = null) + { + Action<string> screenshotAction = delegate { }; + if (testContext != null) { + testContext.ReproStep (string.Format ("Add NuGet package '{0}'", packageOptions.PackageName), packageOptions); + screenshotAction = testContext.TakeScreenShot; + } + AddUpdatePackage (packageOptions, screenshotAction, false); + } + + public static void UpdatePackage (NuGetPackageOptions packageOptions, UITestBase testContext = null) { - var nuget = new NuGetController (takeScreenshot); + Action<string> screenshotAction = delegate { }; + if (testContext != null) { + testContext.ReproStep (string.Format ("Update NuGet package '{0}'", packageOptions.PackageName), packageOptions); + screenshotAction = testContext.TakeScreenShot; + } + AddUpdatePackage (packageOptions, screenshotAction, true); + } + + public static void UpdateAllNuGetPackages (UITestBase testContext = null) + { + Session.ExecuteCommand ("MonoDevelop.PackageManagement.Commands.UpdateAllPackagesInSolution"); + WaitForNuGet.UpdateSuccess (string.Empty); + if (testContext != null) + testContext.TakeScreenShot ("All-NuGet-Packages-Updated"); + } + + static void AddUpdatePackage (NuGetPackageOptions packageOptions, Action<string> takeScreenshot, bool isUpdate = false) + { + packageOptions.PrintData (); + var nuget = new NuGetController (takeScreenshot, isUpdate); nuget.Open (); nuget.EnterSearchText (packageOptions.PackageName, packageOptions.Version, packageOptions.IsPreRelease); - nuget.SelectResultByPackageName (packageOptions.PackageName, packageOptions.Version); + for (int i = 0; i < packageOptions.RetryCount; i++) { + try { + nuget.SelectResultByPackageName (packageOptions.PackageName, packageOptions.Version); + break; + } catch (NuGetException e) { + if (i == packageOptions.RetryCount - 1) + Assert.Inconclusive ("Unable to find NuGet package, could be network related.", e); + } + } nuget.ClickAdd (); - Ide.WaitForStatusMessage (new [] { - string.Format ("{0} successfully added.", packageOptions.PackageName) - }); - if (takeScreenshot != null) - takeScreenshot ("Package-Added"); + Session.WaitForNoElement (nugetWindow); + takeScreenshot ("NuGet-Update-Is-"+isUpdate); + try { + WaitForNuGet.Success (packageOptions.PackageName, isUpdate ? NuGetOperations.Update : NuGetOperations.Add); + } catch (TimeoutException e) { + takeScreenshot ("Wait-For-NuGet-Operation-Failed"); + throw; + } + takeScreenshot ("NuGet-Operation-Finished"); } - public NuGetController (Action<string> takeScreenshot = null) + public NuGetController (Action<string> takeScreenshot = null, bool isUpdate = false) { this.takeScreenshot = takeScreenshot ?? delegate { }; + this.isUpdate = isUpdate; - nugetWindow = c => c.Window ().Marked ("Add Packages"); addPackageButton = c => nugetWindow (c).Children ().Button ().Text ("Add Package"); + updatePackageButton = c => nugetWindow (c).Children ().Button ().Text ("Update Package"); resultList = c => nugetWindow (c).Children ().TreeView ().Model (); includePreRelease = c => nugetWindow (c).Children ().CheckButton ().Text ("Show pre-release packages"); } @@ -112,18 +147,18 @@ namespace UserInterfaceTests var found = Session.Query (c => nugetWindow (c).Children ().CheckType (typeof(Gtk.Label)).Text (packageName)).Length > 0; if (version != null) { found = found && (Session.Query (c => nugetWindow (c).Children ().CheckType (typeof(Gtk.Label)).Text (version)).Length > 0); - if (found) - return; } + if (found) + return; } takeScreenshot ("Package-Failed-To-Be-Found"); - Assert.Fail ("No package '{0}' with version: '{1}' found", packageName, version); + throw new NuGetException (string.Format ("No package '{0}' with version: '{1}' found", packageName, version)); } public void ClickAdd () { WaitForAddButton (true); - Assert.IsTrue (Session.ClickElement (addPackageButton)); + Assert.IsTrue (Session.ClickElement (isUpdate ? updatePackageButton : addPackageButton)); Session.WaitForElement (IdeQuery.TextArea); } @@ -138,7 +173,7 @@ namespace UserInterfaceTests if (enabled == null) Session.WaitForElement (addPackageButton); else - Session.WaitForElement (c => addPackageButton (c).Sensitivity (enabled.Value), 10000); + Session.WaitForElement (c => (isUpdate? updatePackageButton(c) : addPackageButton (c)).Sensitivity (enabled.Value), 30000); } } } diff --git a/main/tests/UserInterfaceTests/Controllers/NuGetOptions.cs b/main/tests/UserInterfaceTests/Controllers/NuGetOptions.cs new file mode 100644 index 0000000000..9fb53d57cb --- /dev/null +++ b/main/tests/UserInterfaceTests/Controllers/NuGetOptions.cs @@ -0,0 +1,179 @@ +// +// NuGetOptions.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Collections.Generic;
+
+namespace UserInterfaceTests +{ + public class NuGetPackageOptions + { + public NuGetPackageOptions () + { + RetryCount = 3; + } + + public string PackageName { get; set;} + + public string Version { get; set;} + + public bool IsPreRelease { get; set;} + + public int RetryCount { get; set;} + + public override string ToString () + { + return string.Format ("PackageName={0}, Version={1}, IsPreRelease={2}, RetryCount={3}", + PackageName, Version, IsPreRelease, RetryCount); + } + } + + public enum NuGetOperations + { + Add, + Remove, + Update + } + + public class WaitForNuGet + { + public WaitForNuGet () + { + TimeOutSeconds = 180; + PollStepSeconds = 1; + } + + public NuGetOperations Operation { get; set;} + + public string PackageName { get; set;} + + public bool WaitForSuccess { get; set;} + + public bool WaitForWarning { get; set;} + + public bool WaitForError { get; set;} + + public int TimeOutSeconds { get; set;} + + public int PollStepSeconds { get; set;} + + public override string ToString () + { + return string.Format ("Operation={0}, PackageName={1}, WaitForSuccess={2}, WaitForWarning={3}, WaitForError={4}, TimeOutSeconds={5}, PollStepSeconds={6}", + Operation, PackageName, WaitForSuccess, WaitForWarning, WaitForError, TimeOutSeconds, PollStepSeconds); + } + + public static void UpdateSuccess (string packageName, bool waitForWarning = true, UITestBase testContext = null) + { + Success (packageName, NuGetOperations.Update, waitForWarning, testContext); + } + + public static void AddSuccess (string packageName, bool waitForWarning = true, UITestBase testContext = null) + { + Success (packageName, NuGetOperations.Add, waitForWarning, testContext); + } + + public static void Success (string packageName, NuGetOperations operation, bool waitForWarning = true, UITestBase testContext = null) + { + var waitPackage = new WaitForNuGet { + Operation = operation, + PackageName = packageName, + WaitForSuccess = true, + WaitForWarning = waitForWarning + }; + if (testContext != null) { + testContext.ReproStep (string.Format ("Wait for one of these messages:\n\t{0}", + string.Join ("\t\n", waitPackage.ToMessages ()))); + } + waitPackage.Wait (); + } + + public void Wait () + { + Ide.WaitForStatusMessage (ToMessages (), TimeOutSeconds, PollStepSeconds); + } + + public string [] ToMessages () + { + if ((WaitForSuccess | WaitForWarning | WaitForError) == false) + throw new ArgumentException ("Atleast one of the 'WaitForSuccess', 'WaitForWarning', 'WaitForError' needs to be true"); + + List<string> waitForMessages = new List<string> (); + + if (WaitForSuccess) { + if (Operation == NuGetOperations.Add) { + waitForMessages.Add (string.Format ("{0} successfully added.", PackageName)); + waitForMessages.Add ("Packages successfully added."); + waitForMessages.Add ("packages successfully added."); + } + if (Operation == NuGetOperations.Update) { + waitForMessages.Add (string.Format ("{0} is up to date.", PackageName)); + waitForMessages.Add (string.Format ("{0} successfully updated.", PackageName)); + waitForMessages.Add ("Packages successfully updated."); + waitForMessages.Add ("packages successfully updated."); + waitForMessages.Add ("successfully updated."); + waitForMessages.Add ("Packages are up to date."); + } + if (Operation == NuGetOperations.Remove) { + waitForMessages.Add (string.Format ("{0} successfully removed.", PackageName)); + } + } + + if (WaitForWarning) { + if (Operation == NuGetOperations.Add) { + waitForMessages.Add (string.Format ("{0} added with warnings.", PackageName)); + waitForMessages.Add ("Packages added with warnings."); + waitForMessages.Add ("packages added with warnings."); + } + if (Operation == NuGetOperations.Update) { + waitForMessages.Add (string.Format ("{0} updated with warnings.", PackageName)); + waitForMessages.Add ("Packages updated with warnings."); + waitForMessages.Add ("packages updated with warnings."); + waitForMessages.Add ("No update found but warnings were reported."); + waitForMessages.Add ("No updates found but warnings were reported."); + } + if (Operation == NuGetOperations.Remove) { + waitForMessages.Add (string.Format ("{0} removed with warnings.", PackageName)); + } + } + + if (WaitForError) { + if (Operation == NuGetOperations.Add) { + waitForMessages.Add (string.Format ("Could not add {0}.", PackageName)); + waitForMessages.Add ("Could not add packages."); + } + if (Operation == NuGetOperations.Update) { + waitForMessages.Add (string.Format ("Could not update {0}.", PackageName)); + waitForMessages.Add ("Could not update packages."); + } + if (Operation == NuGetOperations.Remove) { + waitForMessages.Add (string.Format ("Could not remove {0}.", PackageName)); + } + } + return waitForMessages.ToArray (); + } + } +} + diff --git a/main/tests/UserInterfaceTests/Controllers/OptionsController.cs b/main/tests/UserInterfaceTests/Controllers/OptionsController.cs new file mode 100644 index 0000000000..7a3c9cc0eb --- /dev/null +++ b/main/tests/UserInterfaceTests/Controllers/OptionsController.cs @@ -0,0 +1,148 @@ +// +// ProjectOptionsController.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using MonoDevelop.Components.AutoTest; +using MonoDevelop.Ide.Commands; + +namespace UserInterfaceTests +{ + public class ProjectOptionsController : OptionsController + { + readonly static Func<AppQuery, AppQuery> windowQuery = c => c.Window ().Marked ("MonoDevelop.Ide.Projects.ProjectOptionsDialog"); + + readonly string solutionName; + readonly string projectName; + + public ProjectOptionsController (string solutionName, string projectName, UITestBase testContext = null) : base (windowQuery,testContext) + { + this.solutionName = solutionName; + this.projectName = projectName; + } + + public ProjectOptionsController (UITestBase testContext = null) : base (windowQuery, testContext) { } + + public void OpenProjectOptions () + { + ReproStep (string.Format ("In Solution Explorer, right click '{0}' and select 'Options'", projectName)); + SolutionExplorerController.SelectProject (solutionName, projectName); + + Session.Query (IdeQuery.TextArea); + Session.ExecuteCommand (ProjectCommands.ProjectOptions); + Session.WaitForElement (windowQuery); + TakeScreenshot ("Opened-ProjectOptionsDialog"); + } + } + + public class PreferencesController : OptionsController + { + readonly static Func<AppQuery, AppQuery> windowQuery = c => c.Window ().Marked ("Preferences"); + + public PreferencesController (Action<string> takeScreenshot = null) : base (windowQuery, takeScreenshot) {} + + public void Open () + { + Session.ExecuteCommand (EditCommands.MonodevelopPreferences); + Session.WaitForElement (windowQuery); + TakeScreenshot ("Opened-Preferences-Window"); + } + + public static void SetAuthorInformation (string name = null, string email = null , string copyright = null, + string company = null, string trademark = null, Action<string> takeScreenshot = null) + { + takeScreenshot = takeScreenshot ?? new Action<string> (delegate {}); + + if (name == null && email == null && copyright == null && company == null && trademark == null) + throw new ArgumentNullException ("Atleast one of these arguments need to be not null: name, email, copyright, company, trademark"); + + var prefs = new PreferencesController (); + prefs.Open (); + prefs.SelectPane ("Author Information"); + prefs.SetEntry ("nameEntry", name, "Name", takeScreenshot); + prefs.SetEntry ("emailEntry", email, "Email", takeScreenshot); + prefs.SetEntry ("copyrightEntry", copyright, "Copyright", takeScreenshot); + prefs.SetEntry ("companyEntry", company, "Company", takeScreenshot); + prefs.SetEntry ("trademarkEntry", trademark, "Trademark", takeScreenshot); + prefs.ClickOK (); + } + } + + public abstract class OptionsController + { + protected static AutoTestClientSession Session { + get { return TestService.Session; } + } + + protected Action<string> TakeScreenshot; + readonly UITestBase testContext; + readonly Func<AppQuery, AppQuery> windowQuery; + + protected OptionsController (Func<AppQuery, AppQuery> windowQuery, UITestBase testContext) : this (windowQuery, testContext.TakeScreenShot) + { + this.testContext = testContext; + } + + protected OptionsController (Func<AppQuery, AppQuery> windowQuery, Action<string> takeScreenshot = null) + { + this.windowQuery = windowQuery; + TakeScreenshot = Util.GetNonNullAction (takeScreenshot); + } + + protected void ReproStep (string stepDescription, params object[] info) + { + testContext.ReproStep (stepDescription, info); + } + + public void SelectPane (string name) + { + ReproStep (string.Format ("Select pane: '{0}'", name)); + string.Format ("Selected Pane :{0}", name).PrintData (); + Session.SelectElement (c => windowQuery (c).Children ().Marked ( + "MonoDevelop.Components.HeaderBox").Children ().TreeView ().Model ().Children ().Property ("Label", name)); + } + + protected void SetEntry (string entryName, string entryValue, string stepName, Action<string> takeScreenshot) + { + if (entryValue != null) { + Session.EnterText (c => c.Marked (entryName), entryValue); + Session.WaitForElement (c => c.Marked (entryName).Text (entryValue)); + takeScreenshot (string.Format("{0}-Entry-Set", stepName)); + } + } + + public void ClickOK () + { + ReproStep ("Click OK"); + Session.ClickElement (c => windowQuery (c).Children ().Button ().Text ("OK")); + } + + public void ClickCancel () + { + ReproStep ("Click Cancel"); + Session.ClickElement (c => windowQuery (c).Children ().Button ().Text ("Cancel")); + } + } +} + diff --git a/main/tests/UserInterfaceTests/Controllers/SolutionExplorerController.cs b/main/tests/UserInterfaceTests/Controllers/SolutionExplorerController.cs index 0afd044380..abd0a1f69b 100644 --- a/main/tests/UserInterfaceTests/Controllers/SolutionExplorerController.cs +++ b/main/tests/UserInterfaceTests/Controllers/SolutionExplorerController.cs @@ -24,7 +24,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using System.Linq; using MonoDevelop.Components.AutoTest; +using System.Collections.Generic; namespace UserInterfaceTests { @@ -39,12 +41,68 @@ namespace UserInterfaceTests public static Func<AppQuery, AppQuery> GetSolutionQuery (string solutionLabel) { - return c => topLevel (c).Children().Property ("Label", solutionLabel).Index (0); + return c => topLevel (c).Children (false).Index (0).Property ("Label", solutionLabel); } public static Func<AppQuery, AppQuery> GetProjectQuery (string solutionLabel, string projectLabel) { - return c => topLevel (c).Children().Property ("Label", solutionLabel).Children ().Property ("Label", projectLabel).Index (0); + return c => topLevel (c).Children (false).Index (0).Property ("Label", solutionLabel).Children (false).Property ("Label", projectLabel).Index (0); + } + + public static bool Select (params string[] selectionTree) + { + string.Join (" > ", selectionTree).PrintData (); + Func<AppQuery, AppQuery> query = GetNodeQuery (selectionTree); + return Session.SelectElement (GetNodeQuery (selectionTree)) && Session.WaitForElement (c => query (c).Selected ()).Any (); + } + + public static Func<AppQuery, AppQuery> GetNodeQuery (params string[] selectionTree) + { + var funcs = new List<Func<AppQuery, AppQuery>> (); + funcs.Add (topLevel); + foreach (var nodeName in selectionTree) { + var lastFunc = funcs.Last (); + funcs.Add (c => lastFunc (c).Children (false).Property ("Label", nodeName).Index (0)); + } + return funcs.Last (); + } + + public static bool SelectSolution (string solutionName, UITestBase testContext = null) + { + LogReproSteps (testContext, string.Format ("Under Solution Explorer, select Solution '{0}'", solutionName.StripBold ())); + return Select (solutionName); + } + + public static bool SelectProject (string solutionName, string projectName, UITestBase testContext = null) + { + LogReproSteps (testContext, string.Format ("Under Solution Explorer, select Project '{0}' under '{1}'", projectName.StripBold (), solutionName.StripBold ())); + return Select (solutionName, projectName); + } + + public static bool SelectReferenceFolder (string solutionName, string projectName, UITestBase testContext = null) + { + LogReproSteps (testContext, string.Format ("Under Solution Explorer, expand References node under '{0}'> '{1}'", projectName.StripBold (), solutionName.StripBold ())); + return Select (solutionName, projectName, "References"); + } + + public static bool SelectSingleReference (string solutionName, string projectName, string referenceName, bool fromPackage = false, UITestBase testContext = null) + { + LogReproSteps (testContext, string.Format ("Under Solution Explorer, select NuGet package '{0}' under '{1}' > '{2}' > From Packages", + referenceName, projectName.StripBold (), solutionName.StripBold ())); + return fromPackage ? Select (solutionName, projectName, "From Packages", referenceName) : Select (solutionName, projectName, referenceName); + } + + public static bool SelectPackage (string solutionName, string projectName, string package, UITestBase testContext = null) + { + LogReproSteps (testContext, string.Format ("Under Solution Explorer, select package '{0}' under '{1}' > '{2}' > 'Packages'", package, projectName.StripBold (), solutionName.StripBold ())); + return Select (solutionName, projectName, "Packages", package); + } + + static void LogReproSteps (UITestBase testContext, string message, params object[] info) + { + if (testContext != null) { + testContext.ReproStep (message, info); + } } } } diff --git a/main/tests/UserInterfaceTests/CreateBuildTemplatesTestBase.cs b/main/tests/UserInterfaceTests/CreateBuildTemplatesTestBase.cs index 806cad1800..914d78b0da 100644 --- a/main/tests/UserInterfaceTests/CreateBuildTemplatesTestBase.cs +++ b/main/tests/UserInterfaceTests/CreateBuildTemplatesTestBase.cs @@ -1,8 +1,9 @@ -// -// SimpleTest.cs +// +// CreateBuildTemplatesTestBase.cs // // Author: // Lluis Sanchez Gual <lluis@novell.com> +// Manish Sinha <manish.sinha@xamarin.com> // // Copyright (c) 2010 Novell, Inc (http://www.novell.com) // @@ -29,8 +30,7 @@ using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; using System.Threading; - -using MonoDevelop.Core; +using MonoDevelop.Components.AutoTest; using NUnit.Framework; namespace UserInterfaceTests @@ -92,8 +92,7 @@ namespace UserInterfaceTests TakeScreenShot ("BeforeBuildActionFailed"); Assert.Fail (e.ToString ()); } - - OnBuildTemplate (); + OnBuildTemplate ((int)projectDetails.BuildTimeout.TotalSeconds); } catch (Exception e) { TakeScreenShot ("TestFailedWithGenericException"); Assert.Fail (e.ToString ()); @@ -105,26 +104,44 @@ namespace UserInterfaceTests public void CreateProject (TemplateSelectionOptions templateOptions, ProjectDetails projectDetails, GitOptions gitOptions = null, object miscOptions = null) { + PrintToTestRunner (templateOptions, projectDetails, gitOptions, miscOptions); + ReproStep ("Create a new project", templateOptions, projectDetails, gitOptions, miscOptions); var newProject = new NewProjectController (); - newProject.Open (); + + if (projectDetails.AddProjectToExistingSolution) + newProject.Open (projectDetails.SolutionName); + else + newProject.Open (); TakeScreenShot ("Open"); OnSelectTemplate (newProject, templateOptions); OnEnterTemplateSpecificOptions (newProject, projectDetails.ProjectName, miscOptions); - + OnEnterProjectDetails (newProject, projectDetails, gitOptions, miscOptions); - OnClickCreate (newProject); + OnClickCreate (newProject, projectDetails); + + FoldersToClean.Add (projectDetails.SolutionLocation); } protected virtual void OnSelectTemplate (NewProjectController newProject, TemplateSelectionOptions templateOptions) { - Assert.IsTrue (newProject.SelectTemplateType (templateOptions.CategoryRoot, templateOptions.Category)); + if (!newProject.SelectTemplateType (templateOptions.CategoryRoot, templateOptions.Category)) { + throw new TemplateSelectionException (string.Format ("Failed to select Category '{0}' under '{1}'", + templateOptions.Category, templateOptions.CategoryRoot)); + } TakeScreenShot ("TemplateCategorySelected"); - Assert.IsTrue (newProject.SelectTemplate (templateOptions.TemplateKindRoot, templateOptions.TemplateKind)); + + if (!newProject.SelectTemplate (templateOptions.TemplateKindRoot, templateOptions.TemplateKind)) { + throw new TemplateSelectionException (string.Format ("Failed to select Template '{0}' under '{1}'", + templateOptions.TemplateKind, templateOptions.TemplateKindRoot)); + } TakeScreenShot ("TemplateSelected"); - Assert.IsTrue (newProject.Next ()); + + if (!newProject.Next ()) { + throw new TemplateSelectionException ("Clicking Next failed after selecting template"); + } TakeScreenShot ("NextAfterTemplateSelected"); } @@ -133,38 +150,98 @@ namespace UserInterfaceTests protected virtual void OnEnterProjectDetails (NewProjectController newProject, ProjectDetails projectDetails, GitOptions gitOptions = null, object miscOptions = null) { - Assert.IsTrue (newProject.SetProjectName (projectDetails.ProjectName)); + if (!newProject.SetProjectName (projectDetails.ProjectName, projectDetails.AddProjectToExistingSolution)) { + throw new CreateProjectException (string.Format ("Failed at entering ProjectName as '{0}'", projectDetails.ProjectName)); + } if (!string.IsNullOrEmpty (projectDetails.SolutionName)) { - Assert.IsTrue (newProject.SetSolutionName (projectDetails.SolutionName)); + if (!newProject.SetSolutionName (projectDetails.SolutionName, projectDetails.AddProjectToExistingSolution)) { + throw new CreateProjectException (string.Format ("Failed at entering SolutionName as '{0}'", projectDetails.SolutionName)); + } } if (!string.IsNullOrEmpty (projectDetails.SolutionLocation)) { - Assert.IsTrue (newProject.SetSolutionLocation (projectDetails.SolutionLocation)); + if (!newProject.SetSolutionLocation (projectDetails.SolutionLocation)) { + throw new CreateProjectException (string.Format ("Failed at entering SolutionLocation as '{0}'", projectDetails.SolutionLocation)); + } } - Assert.IsTrue (newProject.CreateProjectInSolutionDirectory (projectDetails.ProjectInSolution)); + if (!newProject.CreateProjectInSolutionDirectory (projectDetails.ProjectInSolution)) { + throw new CreateProjectException (string.Format ("Failed at entering ProjectInSolution as '{0}'", projectDetails.ProjectInSolution)); + } - if (gitOptions != null) - Assert.IsTrue (newProject.UseGit (gitOptions)); + if (gitOptions != null && !projectDetails.AddProjectToExistingSolution) { + if (!newProject.UseGit (gitOptions)) { + throw new CreateProjectException (string.Format ("Failed at setting Git as - '{0}'", gitOptions)); + } + } TakeScreenShot ("AfterProjectDetailsFilled"); } - protected virtual void OnClickCreate (NewProjectController newProject) + protected virtual void OnClickCreate (NewProjectController newProject, ProjectDetails projectDetails) { - Session.RunAndWaitForTimer (() => newProject.Next(), "Ide.Shell.SolutionOpened"); + if (projectDetails.AddProjectToExistingSolution) + newProject.Create (); + else + Session.RunAndWaitForTimer (() => newProject.Create (), "Ide.Shell.SolutionOpened"); } protected virtual void OnBuildTemplate (int buildTimeoutInSecs = 180) { + ReproStep ("Build solution"); try { - Assert.IsTrue (Ide.BuildSolution (timeoutInSecs : buildTimeoutInSecs)); + Assert.IsTrue (Ide.BuildSolution (timeoutInSecs : buildTimeoutInSecs), "Build Failed"); TakeScreenShot ("AfterBuildFinishedSuccessfully"); } catch (TimeoutException e) { + Session.DebugObject.Debug ("Build Failed"); + ReproStep (string.Format ("Expected: Build should finish within '{0}' seconds\nActual: Build timed out", buildTimeoutInSecs)); TakeScreenShot ("AfterBuildFailed"); Assert.Fail (e.ToString ()); } } + + protected void IsTemplateSelected (TemplateSelectionOptions templateOptions, string addToExistingSolution = null) + { +// var newProject = new NewProjectController (); +// try { +// newProject.WaitForOpen (); +// } catch (TimeoutException) { +// if (!string.IsNullOrEmpty (addToExistingSolution)) +// newProject.Open (addToExistingSolution); +// else +// newProject.Open (); +// } +// newProject.IsSelected (templateOptions); + } + + protected void WaitForElement (Func<AppQuery, AppQuery> query, string expected, string actual, int timeoutInSecs = 5) + { + try { + Session.WaitForElement (query, timeoutInSecs * 1000); + } catch (TimeoutException) { + ReproStep (expected, actual); + throw; + } + } + + protected void WaitForElement (Action action, string expected, string actual) + { + try { + action (); + } catch (TimeoutException) { + ReproStep (string.Format ("Expected: {0}\nActual:{1}", expected, actual)); + throw; + } + } + + void PrintToTestRunner (TemplateSelectionOptions templateOptions, + ProjectDetails projectDetails, GitOptions gitOptions, object miscOptions) + { + templateOptions.PrintData (); + projectDetails.PrintData (); + gitOptions.PrintData (); + miscOptions.PrintData (); + } } } diff --git a/main/tests/UserInterfaceTests/DialogTests/NewProjectDialogTests.cs b/main/tests/UserInterfaceTests/DialogTests/NewProjectDialogTests.cs index 96f7edf3f0..26253e1ea8 100644 --- a/main/tests/UserInterfaceTests/DialogTests/NewProjectDialogTests.cs +++ b/main/tests/UserInterfaceTests/DialogTests/NewProjectDialogTests.cs @@ -28,7 +28,7 @@ using NUnit.Framework; namespace UserInterfaceTests { - [TestFixture] + [TestFixture, Timeout(60000)] [Category ("Dialog")] [Category ("ProjectDialog")] public class NewProjectDialogTests : CreateBuildTemplatesTestBase @@ -48,6 +48,7 @@ namespace UserInterfaceTests readonly string solutionLocation = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments); [Test] + [Category ("Cycle6")] [TestCase (true, true, true, TestName = "WithGit--WithGitIgnore--WithProjectWithinSolution")] [TestCase (true, true, false, TestName = "WithGit--WithGitIgnore--WithoutProjectWithinSolution")] [TestCase (true, true, true, TestName = "WithGit--WithGitIgnore--WithProjectWithinSolution")] diff --git a/main/tests/UserInterfaceTests/DialogTests/NuGetDialogTests.cs b/main/tests/UserInterfaceTests/DialogTests/NuGetDialogTests.cs index bd97ab3c39..f27c95b8c0 100644 --- a/main/tests/UserInterfaceTests/DialogTests/NuGetDialogTests.cs +++ b/main/tests/UserInterfaceTests/DialogTests/NuGetDialogTests.cs @@ -25,26 +25,36 @@ // THE SOFTWARE. using NUnit.Framework; +using MonoDevelop.Ide.Commands; +using MonoDevelop.Core; +using System.IO; +using System.Xml; +using System; +using System.Collections.Generic; namespace UserInterfaceTests { - [TestFixture] + [TestFixture, Timeout(60000)] [Category ("Dialog")] + [Category ("NuGet")] [Category ("PackagesDialog")] public class NuGetDialogTests : CreateBuildTemplatesTestBase { - [Test] + [Test, Category("Smoke")] + [Description ("Add a single NuGet Package")] public void AddPackagesTest () { CreateProject (); NuGetController.AddPackage (new NuGetPackageOptions { PackageName = "CommandLineParser", - Version = "2.0.1-pre", + Version = "2.0.257-beta", IsPreRelease = true - }); + }, this); } - ProjectDetails CreateProject () + [Test, Timeout(300000), Category ("Cycle6")] + [Description ("When a solution is opened and package updates are available, don't show in status bar")] + public void DontShowPackageUpdatesAvailable () { var templateOptions = new TemplateSelectionOptions { CategoryRoot = OtherCategoryRoot, @@ -53,6 +63,201 @@ namespace UserInterfaceTests TemplateKind = "Console Project" }; var projectDetails = new ProjectDetails (templateOptions); + CreateProject (templateOptions, projectDetails); + NuGetController.AddPackage (new NuGetPackageOptions { + PackageName = "CommandLineParser", + Version = "1.9.3.34", + IsPreRelease = false + }, this); + + string solutionFolder = GetSolutionDirectory (); + string solutionPath = Path.Combine (solutionFolder, projectDetails.SolutionName+".sln"); + var projectPath = Path.Combine (solutionFolder, projectDetails.ProjectName, projectDetails.ProjectName + ".csproj"); + Assert.IsTrue (File.Exists (projectPath)); + + Workbench.CloseWorkspace (this); + + Workbench.OpenWorkspace (solutionPath, this); + try { + const string expected = "When a solution is opened and package updates are available, it don't show in status bar"; + ReproStep (expected); + Ide.WaitForPackageUpdate (); + var failureMessage = string.Format ("Expected: {0}\nActual: {1}", + expected, "When a solution is opened and package updates are available, it shows in status bar"); + ReproStep (failureMessage); + Assert.Fail (failureMessage); + } catch (TimeoutException) { + Session.DebugObject.Debug ("WaitForPackageUpdate throws TimeoutException as expected"); + } + Ide.WaitForSolutionLoaded (); + TakeScreenShot ("Solution-Ready"); + } + + [Test, Category("Smoke")] + [Description ("Add a single NuGet Package and check if it's readme.txt opens")] + public void TestReadmeTxtOpens () + { + CreateProject (); + NuGetController.AddPackage (new NuGetPackageOptions { + PackageName = "RestSharp", + Version = "105.2.3", + IsPreRelease = true + }, this); + WaitForNuGetReadmeOpened (); + } + + [Test, Category ("Cycle6")] + [Description ("Add a single NuGet Package. Check if readme.txt opens even when updating")] + public void TestReadmeTxtUpgradeOpens () + { + CreateProject (); + NuGetController.AddPackage (new NuGetPackageOptions { + PackageName = "RestSharp", + Version = "105.2.2", + IsPreRelease = true + }, this); + WaitForNuGetReadmeOpened (); + + Session.ExecuteCommand (FileCommands.CloseFile); + Session.WaitForElement (IdeQuery.TextArea); + TakeScreenShot ("About-To-Update-Package"); + NuGetController.UpdatePackage (new NuGetPackageOptions { + PackageName = "RestSharp", + Version = "105.2.3", + IsPreRelease = true + }, this); + WaitForNuGetReadmeOpened (); + } + + [Test, Category("Smoke"), Category ("Cycle6")] + [Timeout (90000)] + [Description ("When readme.txt from a package has already been opened, adding same package to another project should not open readme.txt")] + public void TestDontOpenReadmeOpenedInOther () + { + var packageInfo = new NuGetPackageOptions { + PackageName = "RestSharp", + Version = "105.2.3", + IsPreRelease = true + }; + + var projectDetails = CreateProject (); + NuGetController.AddPackage (packageInfo, this); + WaitForNuGetReadmeOpened (); + Session.ExecuteCommand (FileCommands.CloseFile); + + var pclTemplateOptions = new TemplateSelectionOptions { + CategoryRoot = "Other", + Category = ".NET", + TemplateKindRoot = "General", + TemplateKind = "Library" + }; + var pclProjectDetails = ProjectDetails.ToExistingSolution (projectDetails.SolutionName, + GenerateProjectName (pclTemplateOptions.TemplateKind)); + CreateProject (pclTemplateOptions, pclProjectDetails); + Ide.WaitForIdeIdle (30); + + SolutionExplorerController.SelectProject (projectDetails.SolutionName, pclProjectDetails.ProjectName); + NuGetController.AddPackage (packageInfo, this); + try { + WaitForNuGetReadmeOpened (false); + var failureMessage = string.Format ("Expected: {0}\nActual:{1}", + "readme.txt tab should not open", "readme.txt tab opens"); + ReproStep (failureMessage); + Assert.Fail (failureMessage); + } catch (TimeoutException) { + Session.DebugObject.Debug ("readme.txt tab failed to open as expected"); + } + } + + [Test, Category ("Cycle6")] + [Description ("Add a package with powershell scripts and assert that Xamarin Studio doesn't report warnings "+ + "when trying to add powershell scripts to Xamarin Studio")] + public void TestDontShowWarningWithPowerShellScripts () + { + CreateProject (); + NuGetController.AddPackage (new NuGetPackageOptions { + PackageName = "Newtonsoft.Json", + }, this); + WaitForNuGet.Success ("Newtonsoft.Json", NuGetOperations.Add, false, this); + TakeScreenShot ("NewtonSoftJson-Package-Added-Without-Warning"); + } + + [Test, Timeout (300000), Category ("Cycle6")] + [Description ("When a NuGet package is updated, the 'Local Copy' value should be preserved")] + public void TestLocalCopyPreservedUpdate () + { + var templateOptions = new TemplateSelectionOptions { + CategoryRoot = OtherCategoryRoot, + Category = ".NET", + TemplateKindRoot = GeneralKindRoot, + TemplateKind = "Console Project" + }; + var projectDetails = new ProjectDetails (templateOptions); + CreateProject (templateOptions, projectDetails); + NuGetController.AddPackage (new NuGetPackageOptions { + PackageName = "CommandLineParser", + Version = "1.9.71", + IsPreRelease = false + }, this); + + string solutionFolder = GetSolutionDirectory (); + string solutionPath = Path.Combine (solutionFolder, projectDetails.SolutionName+".sln"); + var projectPath = Path.Combine (solutionFolder, projectDetails.ProjectName, projectDetails.ProjectName + ".csproj"); + Assert.IsTrue (File.Exists (projectPath)); + + ReproStep ("Check 'Local Copy' on CommandLine package under References"); + + Workbench.CloseWorkspace (this); + + AddOrCheckLocalCopy (projectPath, true); + + Workbench.OpenWorkspace (solutionPath, this); + + NuGetController.UpdateAllNuGetPackages (this); + + ReproStep ("Check if CommandLine package under References has 'Local Copy' checked"); + AddOrCheckLocalCopy (projectPath, false); + } + + void AddOrCheckLocalCopy (string projectPath, bool addLocalCopy) + { + using (var stream = new FileStream (projectPath, FileMode.Open, FileAccess.ReadWrite)) { + var xmlDoc = new XmlDocument(); + xmlDoc.Load(stream); + var ns = "http://schemas.microsoft.com/developer/msbuild/2003"; + XmlNamespaceManager xnManager = new XmlNamespaceManager(xmlDoc.NameTable); + xnManager.AddNamespace("ui", ns); + XmlNode root = xmlDoc.DocumentElement; + var uitest = root.SelectSingleNode ("//ui:Reference[@Include=\"CommandLine\"]", xnManager); + Assert.IsNotNull (uitest, "Cannot find CommandLine package reference in file: "+projectPath); + var privateUITestNode = uitest.SelectSingleNode ("./ui:Private", xnManager); + + if (addLocalCopy) { + Assert.IsNull (privateUITestNode, uitest.InnerXml, "CommandLine package is already set to 'No Local Copy'"); + var privateNode = xmlDoc.CreateElement ("Private", ns); + privateNode.InnerText = "False"; + uitest.AppendChild (privateNode); + stream.SetLength (0); + xmlDoc.Save (stream); + stream.Flush (); + } else { + Assert.IsNotNull (privateUITestNode, "Cannot find CommandLine package with 'No Local Copy' set"); + Assert.AreEqual (privateUITestNode.InnerText, "False"); + } + stream.Close (); + } + } + + + ProjectDetails CreateProject (TemplateSelectionOptions templateOptions = null, ProjectDetails projectDetails = null) + { + templateOptions = templateOptions ?? new TemplateSelectionOptions { + CategoryRoot = OtherCategoryRoot, + Category = ".NET", + TemplateKindRoot = GeneralKindRoot, + TemplateKind = "Console Project" + }; + projectDetails = projectDetails ?? new ProjectDetails (templateOptions); CreateProject (templateOptions, projectDetails, new GitOptions { UseGit = true, UseGitIgnore = true}); @@ -60,6 +265,20 @@ namespace UserInterfaceTests FoldersToClean.Add (projectDetails.SolutionLocation); return projectDetails; } + + void WaitForNuGetReadmeOpened (bool expectSuccess = true) + { + ReproStep ("Wait for tab with readme.txt to be opened"); + try { + Session.WaitForElement (c => c.Window ().Marked ("MonoDevelop.Ide.Gui.DefaultWorkbench").Property ("TabControl.CurrentTab.Text", "readme.txt")); + } catch (TimeoutException) { + if (expectSuccess) { + ReproStep (string.Format ("Expected: {0}\nActual: {1}", + "readme.txt tab should open", "readm.txt tab did not open")); + } + throw; + } + } } } diff --git a/main/tests/UserInterfaceTests/Exceptions/CreateProjectException.cs b/main/tests/UserInterfaceTests/Exceptions/CreateProjectException.cs new file mode 100644 index 0000000000..0e91464f13 --- /dev/null +++ b/main/tests/UserInterfaceTests/Exceptions/CreateProjectException.cs @@ -0,0 +1,37 @@ +// +// CreateProjectException.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; + +namespace UserInterfaceTests +{ + public class CreateProjectException : Exception + { + public CreateProjectException (string message): base (message) + { + } + } +} + diff --git a/main/tests/UserInterfaceTests/Exceptions/NuGetException.cs b/main/tests/UserInterfaceTests/Exceptions/NuGetException.cs new file mode 100644 index 0000000000..935dc6d3b4 --- /dev/null +++ b/main/tests/UserInterfaceTests/Exceptions/NuGetException.cs @@ -0,0 +1,41 @@ +// +// NuGetException.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; + +namespace UserInterfaceTests +{ + public class NuGetException : Exception + { + public NuGetException (string message) : base (message) + { + } + + public NuGetException (string message, Exception innerExceotion) : base (message, innerExceotion) + { + } + } +} + diff --git a/main/tests/UserInterfaceTests/Exceptions/TemplateSelectionException.cs b/main/tests/UserInterfaceTests/Exceptions/TemplateSelectionException.cs new file mode 100644 index 0000000000..041f4bb5e5 --- /dev/null +++ b/main/tests/UserInterfaceTests/Exceptions/TemplateSelectionException.cs @@ -0,0 +1,37 @@ +// +// TemplateSelectionException.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; + +namespace UserInterfaceTests +{ + public class TemplateSelectionException : Exception + { + public TemplateSelectionException (string message) : base (message) + { + } + } +} + diff --git a/main/tests/UserInterfaceTests/Ide.cs b/main/tests/UserInterfaceTests/Ide.cs index 14a4b86857..37af208fa8 100644 --- a/main/tests/UserInterfaceTests/Ide.cs +++ b/main/tests/UserInterfaceTests/Ide.cs @@ -1,5 +1,5 @@ // -// IdeApi.cs +// Ide.cs // // Author: // Lluis Sanchez Gual <lluis@novell.com> @@ -26,6 +26,7 @@ using System; using System.Threading; +using System.Linq; using MonoDevelop.Core; using MonoDevelop.Core.Instrumentation; @@ -33,11 +34,8 @@ using MonoDevelop.Ide.Commands; using MonoDevelop.Components.AutoTest; using NUnit.Framework; - -using Gdk; -using System.Linq; - - +using System.Collections.Generic;
+
namespace UserInterfaceTests { public static class Ide @@ -48,12 +46,13 @@ namespace UserInterfaceTests public static void OpenFile (FilePath file) { - Session.GlobalInvoke ("MonoDevelop.Ide.IdeApp.Workbench.OpenDocument", (string) file, true); + Session.RunAndWaitForTimer (() => Session.GlobalInvoke ("MonoDevelop.Ide.IdeApp.Workbench.OpenDocument", (string)file, true), "Ide.Shell.DocumentOpened"); Assert.AreEqual (file, GetActiveDocumentFilename ()); } public static void CloseAll () { + Session.ExecuteCommand (FileCommands.SaveAll); Session.ExecuteCommand (FileCommands.CloseWorkspace); Session.ExitApp (); } @@ -63,15 +62,13 @@ namespace UserInterfaceTests return Session.GetGlobalValue<FilePath> ("MonoDevelop.Ide.IdeApp.Workbench.ActiveDocument.FileName"); } - public static bool BuildSolution (bool isPass = true, int timeoutInSecs = 180) + public static bool BuildSolution (bool isPass = true, int timeoutInSecs = 360) { - Session.RunAndWaitForTimer (() => Session.ExecuteCommand (ProjectCommands.BuildSolution), - "Ide.Shell.ProjectBuilt", timeout: timeoutInSecs * 1000); - var status = IsBuildSuccessful (); - return isPass == status; + Session.RunAndWaitForTimer (() => Session.ExecuteCommand (ProjectCommands.BuildSolution), "Ide.Shell.ProjectBuilt", timeoutInSecs * 1000); + return isPass == Workbench.IsBuildSuccessful (timeoutInSecs); } - public static void WaitUntil (Func<bool> done, int timeout = 20000, int pollStep = 200) + public static void WaitUntil (Func<bool> done, int timeout = 20000, int pollStep = 200, Func<string> timeoutMessage = null) { do { if (done ()) @@ -80,30 +77,22 @@ namespace UserInterfaceTests Thread.Sleep (pollStep); } while (timeout > 0); - throw new TimeoutException ("Timed out waiting for Function: "+done.Method.Name); + if (timeoutMessage != null) { + throw new TimeoutException ("Timed out waiting for Function: " + done.Method.Name + " Message: " + timeoutMessage ()); + } else { + throw new TimeoutException ("Timed out waiting for Function: " + done.Method.Name); + } } - //no saner way to do this - public static string GetStatusMessage (int timeout = 20000) + public static bool ClickButtonAlertDialog (string buttonText) { if (Platform.IsMac) { - WaitUntil ( - () => Session.GetGlobalValue<string> ("MonoDevelop.Ide.IdeApp.Workbench.RootWindow.StatusBar.text") != string.Empty, - timeout - ); - return (string)Session.GetGlobalValue ("MonoDevelop.Ide.IdeApp.Workbench.RootWindow.StatusBar.text"); + Ide.WaitUntil (() => Session.Query (c => c.Marked ("Xamarin Studio").Marked ("AppKit.NSPanel")).Any ()); + return Session.ClickElement (c => c.Marked ("AppKit.NSButton").Text (buttonText)); + } else { + Ide.WaitUntil (() => Session.Query (c => c.Window ().Marked ("MonoDevelop.Ide.Gui.Dialogs.GtkAlertDialog")).Any ()); + return Session.ClickElement (c => c.Window ().Marked ("MonoDevelop.Ide.Gui.Dialogs.GtkAlertDialog").Children ().Button ().Text (buttonText)); } - - WaitUntil ( - () => Session.GetGlobalValue<int> ("MonoDevelop.Ide.IdeApp.Workbench.RootWindow.StatusBar.messageQueue.Count") == 0, - timeout - ); - return (string) Session.GetGlobalValue ("MonoDevelop.Ide.IdeApp.Workbench.RootWindow.StatusBar.renderArg.CurrentText"); - } - - public static bool IsBuildSuccessful () - { - return Session.ErrorCount (MonoDevelop.Ide.Tasks.TaskSeverity.Error) == 0; } public static void RunAndWaitForTimer (Action action, string counter, int timeout = 20000) @@ -113,32 +102,51 @@ namespace UserInterfaceTests action (); - WaitUntil (() => c.TotalTime > tt, timeout); + WaitUntil (() => c.TotalTime > tt, timeout, + timeoutMessage: () => "Counter:" + counter + " T1:" + c.TotalTime + " T2:" + tt + " Timeout:" + timeout); } + + public readonly static Action WaitForPackageUpdateOrSaved = delegate { + try { + WaitForPackageUpdate (); + } catch (TimeoutException e1) { + try { + WaitForSolutionLoaded (); + } catch (TimeoutException e2) { + throw new TimeoutException (string.Format ("{0}\n{1}", e1.Message, e2.Message), e1); + } + } + }; + public readonly static Action EmptyAction = delegate { }; + static string[] waitForNuGetMessages = { + "Package updates are available.", + "Packages are up to date.", + "No updates found but warnings were reported.", + "Packages successfully added.", + "Packages successfully updated.", + "Packages added with warnings.", + "Packages updated with warnings."}; + public readonly static Action WaitForPackageUpdate = delegate { - WaitForStatusMessage (new [] { - "Package updates are available.", - "Packages are up to date.", - "No updates found but warnings were reported.", - "Packages successfully updated.", - "Packages updated with warnings."}, - timeoutInSecs: 360, pollStepInSecs: 5); + WaitForStatusMessage (waitForNuGetMessages, timeoutInSecs: 180, pollStepInSecs: 5); }; + public static void WaitForPackageUpdateExtra (List<string> otherMessages) + { + otherMessages.AddRange (waitForNuGetMessages); + WaitForStatusMessage (otherMessages.ToArray (), timeoutInSecs: 180, pollStepInSecs: 5); + } + public readonly static Action WaitForSolutionCheckedOut = delegate { WaitForStatusMessage (new [] {"Solution checked out", "Solution Loaded."}, timeoutInSecs: 360, pollStepInSecs: 5); }; - public static void WaitForSolutionLoaded (Action<string> afterEachStep) - { - WaitForStatusMessage (new [] {"Loading..."}); - afterEachStep ("Loading-Solution"); - WaitForNoStatusMessage (new [] {"Loading..."}); - afterEachStep ("Solution-Loaded"); - } + public readonly static Action WaitForSolutionLoaded = delegate { + WaitForStatusMessage (new [] {"Project saved.", "Solution loaded."}, timeoutInSecs: 120, pollStepInSecs: 5); + }; public static void WaitForStatusMessage (string[] statusMessage, int timeoutInSecs = 240, int pollStepInSecs = 1) { @@ -153,10 +161,71 @@ namespace UserInterfaceTests static void PollStatusMessage (string[] statusMessage, int timeoutInSecs, int pollStepInSecs, bool waitForMessage = true) { Ide.WaitUntil (() => { - var actualStatusMessage = Ide.GetStatusMessage (); - return waitForMessage == (statusMessage.Contains (actualStatusMessage, StringComparer.OrdinalIgnoreCase)); - }, pollStep: pollStepInSecs * 1000, timeout: timeoutInSecs * 1000); + string actualStatusMessage = string.Empty; + try { + actualStatusMessage = Workbench.GetStatusMessage (); + return waitForMessage == (statusMessage.Contains (actualStatusMessage, StringComparer.OrdinalIgnoreCase)); + } catch (TimeoutException e) { + throw new TimeoutException ( + string.Format ("Timed out. Found status message '{0}'\nand expected one of these:\n\t {1}", + actualStatusMessage, string.Join ("\n\t", statusMessage)), e); + } + }, + pollStep: pollStepInSecs * 1000, + timeout: timeoutInSecs * 1000, + timeoutMessage: () => "GetStatusMessage=" + Workbench.GetStatusMessage ()); + } + + static readonly List<string> ignoreStatusMessgaes = new List<string> { + "Saving...", + "Restoring packages for solution...", + "Restoring packages before update...", + "Restoring packages for project...", + "Updating packages in solution...", + "Updating packages in project..." + }; + + public static void WaitForIdeIdle (uint totalTimeoutInSecs = 100, uint idlePeriodInSecs = 10, string[] ignoreMessages = null) + { + uint retriesLeft = (uint)Math.Ceiling ((double)totalTimeoutInSecs/(double)idlePeriodInSecs); + ManualResetEvent resetEvent = new ManualResetEvent (false); + if (ignoreMessages != null) + ignoreStatusMessgaes.AddRange (ignoreMessages); + + var timer = new System.Timers.Timer { + Interval = idlePeriodInSecs * 1000, + AutoReset = true + }; + bool didTimeout = false; + + var initialStatusMessage = Workbench.GetStatusMessage (waitForNonEmpty: false); + timer.Elapsed += (sender, e) => { + if (retriesLeft == 0) { + didTimeout = true; + resetEvent.Set (); + } + + var finalStatusMessage = Workbench.GetStatusMessage (waitForNonEmpty: false); + var isIdle = string.Equals (initialStatusMessage, finalStatusMessage) && !ignoreStatusMessgaes.Contains (finalStatusMessage); + + if (!isIdle) { + retriesLeft--; + initialStatusMessage = finalStatusMessage; + } + if (isIdle) { + resetEvent.Set (); + } + }; + + timer.Start (); + resetEvent.WaitOne (); + timer.Stop (); + timer.AutoReset = false; + timer.Dispose (); + + if (didTimeout) + throw new TimeoutException ("Timeout waiting for IDE to be ready and idle"); } } -}
\ No newline at end of file +} diff --git a/main/tests/UserInterfaceTests/IdeQuery.cs b/main/tests/UserInterfaceTests/IdeQuery.cs index c47068d6ed..69fda74e57 100644 --- a/main/tests/UserInterfaceTests/IdeQuery.cs +++ b/main/tests/UserInterfaceTests/IdeQuery.cs @@ -25,6 +25,7 @@ // THE SOFTWARE. using System; using MonoDevelop.Components.AutoTest; +using MonoDevelop.Core; namespace UserInterfaceTests { @@ -36,6 +37,18 @@ namespace UserInterfaceTests readonly static Func<AppQuery, AppQuery> _editRemoteDialog = c => c.Window ().Marked ("MonoDevelop.VersionControl.Git.EditRemoteDialog"); readonly static Func<AppQuery, AppQuery> _editBranchDialog = c => c.Window ().Marked ("MonoDevelop.VersionControl.Git.EditBranchDialog"); readonly static Func<AppQuery, AppQuery> _textArea = c => c.Window ().Children ().Marked ("Mono.TextEditor.TextArea"); + readonly static Func<AppQuery, AppQuery> _xamarinUpdate = c => c.Marked ("Xamarin Update"); + + readonly static Func<AppQuery, AppQuery> _macRunButton = c => c.Marked ("MonoDevelop.MacIntegration.MainToolbar.RunButton"); + + public static Func<AppQuery, AppQuery> RunButton + { + get { + if (Platform.IsMac) + return _macRunButton; + throw new NotImplementedException ("Run Button is not implemented for Windows"); + } + } public static Func<AppQuery, AppQuery> DefaultWorkbench { @@ -78,6 +91,13 @@ namespace UserInterfaceTests return _textArea; } } + + public static Func<AppQuery, AppQuery> XamarinUpdate + { + get { + return _xamarinUpdate; + } + } } } diff --git a/main/tests/UserInterfaceTests/LogMessageValidator.cs b/main/tests/UserInterfaceTests/LogMessageValidator.cs new file mode 100644 index 0000000000..fc2f875f14 --- /dev/null +++ b/main/tests/UserInterfaceTests/LogMessageValidator.cs @@ -0,0 +1,56 @@ +// +// LogMessageValidator.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.IO; +using NUnit.Framework; +using System.Collections.Generic; + +namespace UserInterfaceTests +{ + public class LogMessageValidator + { + static List<string> invalidLogStrings = new List<string> { + "Gtk-Critical: void gtk_container_remove(GtkContainer , GtkWidget )" + }; + + public static void Validate (string fileName) + { + string readIdeLog = string.Empty; + using (FileStream fileStream = new FileStream (fileName, FileMode.Open, + FileAccess.Read, FileShare.ReadWrite)) { + using (StreamReader streamReader = new StreamReader (fileStream)) { + readIdeLog = streamReader.ReadToEnd (); + } + } + + foreach (var error in invalidLogStrings) { + Assert.IsFalse (readIdeLog.Contains (error), + string.Format ("GTK Error detected in Ide.log file:\n\t{0}",error)); + } + } + } +} + diff --git a/main/tests/UserInterfaceTests/TemplateTestOptions.cs b/main/tests/UserInterfaceTests/TemplateTestOptions.cs index 6385b9928b..370f4237ce 100644 --- a/main/tests/UserInterfaceTests/TemplateTestOptions.cs +++ b/main/tests/UserInterfaceTests/TemplateTestOptions.cs @@ -23,6 +23,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. + using System; namespace UserInterfaceTests @@ -57,6 +58,12 @@ namespace UserInterfaceTests public string TemplateKindRoot { get; set; } public string TemplateKind { get; set; } + + public override string ToString () + { + return string.Format ("CategoryRoot={0}, Category={1}, TemplateKindRoot={2}, TemplateKind={3}", + CategoryRoot, Category, TemplateKindRoot, TemplateKind); + } } public class GitOptions @@ -70,6 +77,11 @@ namespace UserInterfaceTests public bool UseGit { get; set; } public bool UseGitIgnore { get; set; } + + public override string ToString () + { + return string.Format ("UseGit={0}, UseGitIgnore={1}", UseGit, UseGitIgnore); + } } public class ProjectDetails @@ -78,6 +90,7 @@ namespace UserInterfaceTests { SolutionLocation = Util.CreateTmpDir (); ProjectInSolution = true; + BuildTimeout = TimeSpan.FromSeconds (180); } public ProjectDetails (TemplateSelectionOptions templateData) : this () @@ -86,6 +99,16 @@ namespace UserInterfaceTests SolutionName = ProjectName; } + public static ProjectDetails ToExistingSolution (string solutionName, string projectName) + { + return new ProjectDetails { + ProjectName = projectName, + SolutionName = solutionName, + AddProjectToExistingSolution = true, + SolutionLocation = null + }; + } + public string ProjectName { get; set; } public string SolutionName { get; set; } @@ -93,6 +116,16 @@ namespace UserInterfaceTests public string SolutionLocation { get; set; } public bool ProjectInSolution { get; set; } + + public bool AddProjectToExistingSolution { get; set; } + + public TimeSpan BuildTimeout { get; set; } + + public override string ToString () + { + return string.Format ("ProjectName={0}, SolutionName={1}, SolutionLocation={2}, ProjectInSolution={3}, AddProjectToExistingSolution={4}", + ProjectName, SolutionName, SolutionLocation, ProjectInSolution, AddProjectToExistingSolution); + } } public class NewFileOptions @@ -106,6 +139,12 @@ namespace UserInterfaceTests public string FileTypeCategoryRoot { get; set; } public string AddToProjectName { get; set; } + + public override string ToString () + { + return string.Format ("FileName={0}, FileType={1}, FileTypeCategory={2}, FileTypeCategoryRoot={3}, AddToProjectName={4}", + FileName, FileType, FileTypeCategory, FileTypeCategoryRoot, AddToProjectName); + } } } diff --git a/main/tests/UserInterfaceTests/TemplateTests/ASPNETTemplateTests.cs b/main/tests/UserInterfaceTests/TemplateTests/ASPNETTemplateTests.cs index 0ab34f71b6..904726c71d 100644 --- a/main/tests/UserInterfaceTests/TemplateTests/ASPNETTemplateTests.cs +++ b/main/tests/UserInterfaceTests/TemplateTests/ASPNETTemplateTests.cs @@ -35,15 +35,22 @@ namespace UserInterfaceTests { readonly string aspCategory = "ASP.NET"; - [Test] - [TestCase ("Empty ASP.NET MVC Project", BeforeBuildAction.WaitForPackageUpdate, TestName = "TestEmptyASPMVCProject")] - [TestCase ("Empty ASP.NET Project", BeforeBuildAction.None, TestName = "TestEmptyASPProject")] - [TestCase ("ASP.NET MVC Project", BeforeBuildAction.WaitForPackageUpdate, TestName = "TestASPMVCProject")] - [TestCase ("ASP.NET MVC Project with Unit Tests", BeforeBuildAction.WaitForPackageUpdate, TestName = "TestASPMVCProjectWithUnitTests")] - [TestCase ("ASP.NET MVC Razor Project", BeforeBuildAction.WaitForPackageUpdate, TestName = "TestASPMVCMazorProject")] - [TestCase ("ASP.NET MVC Razor Project with Unit Tests", BeforeBuildAction.WaitForPackageUpdate, TestName = "TestASPMVCMazorProjectWithUnitTests")] - [TestCase ("ASP.NET Project", BeforeBuildAction.None, TestName = "TestASPProject")] - public void RunASPTest (string templateName, BeforeBuildAction beforeBuild) + [Test, Timeout (90000)] + [TestCase ("Empty ASP.NET MVC Project", TestName = "TestEmptyASPMVCProject", + Description = "Create and build Empty ASP.NET MVC Project")] + [TestCase ("Empty ASP.NET Project", TestName = "TestEmptyASPProject", + Description = "Create and build Empty ASP.NET MVC Project")] + [TestCase ("ASP.NET MVC Project", TestName = "TestASPMVCProject", + Description = "Create and build ASP.NET MVC Project")] + [TestCase ("ASP.NET MVC Project with Unit Tests", TestName = "TestASPMVCProjectWithUnitTests", + Description = "Create and build ASP.NET MVC Project with Unit Tests")] + [TestCase ("ASP.NET MVC Razor Project", TestName = "TestASPMVCMazorProject", + Description = "Create and build ASP.NET MVC Razor Project")] + [TestCase ("ASP.NET MVC Razor Project with Unit Tests", TestName = "TestASPMVCMazorProjectWithUnitTests", + Description = "Create and build ASP.NET MVC Razor Project with Unit Tests", Category="Smoke")] + [TestCase ("ASP.NET Project", TestName = "TestASPProject", + Description = "Create and build ASP.NET Project")] + public void RunASPTest (string templateName) { var templateOptions = new TemplateSelectionOptions { CategoryRoot = OtherCategoryRoot, @@ -51,7 +58,8 @@ namespace UserInterfaceTests TemplateKindRoot = GeneralKindRoot, TemplateKind = templateName }; - CreateBuildProject (templateOptions, beforeBuild.GetAction ()); + + CreateBuildProject (templateOptions, () => Ide.WaitForIdeIdle (totalTimeoutInSecs: 50)); } } } diff --git a/main/tests/UserInterfaceTests/TemplateTests/DotNetTemplatesTest.cs b/main/tests/UserInterfaceTests/TemplateTests/DotNetTemplatesTest.cs index 53abdb7d70..48eb89b26b 100644 --- a/main/tests/UserInterfaceTests/TemplateTests/DotNetTemplatesTest.cs +++ b/main/tests/UserInterfaceTests/TemplateTests/DotNetTemplatesTest.cs @@ -34,12 +34,13 @@ namespace UserInterfaceTests { readonly string dotNetCategory = ".NET"; - [Test] - [TestCase ("Console Project", BeforeBuildAction.None, TestName = "TestCreateBuildConsoleProject")] - [TestCase ("Gtk# 2.0 Project", BeforeBuildAction.None, TestName = "TestCreateBuildGtkSharp20Project")] - [TestCase ("Library", BeforeBuildAction.None, TestName = "TestCreateBuildLibrary")] - [TestCase ("NUnit Library Project", BeforeBuildAction.WaitForPackageUpdate, TestName = "TestCreateBuildNUnitLibraryProject")] - public void RunDotNetTests (string templateName, BeforeBuildAction beforeBuild) + [Test, Timeout (90000)] + [TestCase ("Console Project", 30, TestName = "TestCreateBuildConsoleProject", Description = "Create and build C# Console Project", Category="Smoke")] + [TestCase ("Gtk# 2.0 Project", 30, TestName = "TestCreateBuildGtkSharp20Project", Description = "Create and build a GTK#2 Project")] + [TestCase ("Library", 30, TestName = "TestCreateBuildLibrary", Description = "Create and build a Library Project")] + [TestCase ("NUnit Library Project", 50, TestName = "TestCreateBuildNUnitLibraryProject", + Description = "Create and build NUnit Library Project", Category="Smoke")] + public void RunDotNetTests (string templateName, int totalTimeoutInSecs) { var templateOptions = new TemplateSelectionOptions { CategoryRoot = OtherCategoryRoot, @@ -47,7 +48,7 @@ namespace UserInterfaceTests TemplateKindRoot = GeneralKindRoot, TemplateKind = templateName }; - CreateBuildProject (templateOptions, beforeBuild.GetAction ()); + CreateBuildProject (templateOptions, () => Ide.WaitForIdeIdle ((uint)totalTimeoutInSecs)); } } } diff --git a/main/tests/UserInterfaceTests/TemplateTests/MiscTemplatesTest.cs b/main/tests/UserInterfaceTests/TemplateTests/MiscTemplatesTest.cs index 196e3392db..8a041ac129 100644 --- a/main/tests/UserInterfaceTests/TemplateTests/MiscTemplatesTest.cs +++ b/main/tests/UserInterfaceTests/TemplateTests/MiscTemplatesTest.cs @@ -28,18 +28,25 @@ using NUnit.Framework; namespace UserInterfaceTests { - [TestFixture] - [Category("Misc")] + [TestFixture, Timeout (60000), Category ("Misc")] public class MiscTemplatesTest : CreateBuildTemplatesTestBase { readonly string miscCategory = "Miscellaneous"; [Test] - [TestCase ("Generic Project", "Generic", TestName = "TestMiscGenericProject")] - [TestCase ("Packaging project", "Generic", TestName = "TestMiscPackagingProject")] - [TestCase ("Shared Library", "C/C++", TestName = "TestMiscCCPlusSharedLibrary")] - [TestCase ("Static Library", "C/C++", TestName = "TestMiscCCPlusStaticLibrary")] - [TestCase ("Console Project", "C/C++", TestName = "TestMiscCCPlusConsoleProject")] + [Platform (Exclude="Win")] + [TestCase ("Shared Library", "C/C++", TestName = "TestMiscCCPlusSharedLibrary", Description = "Create and build Shared C/C++ Library")] + [TestCase ("Static Library", "C/C++", TestName = "TestMiscCCPlusStaticLibrary", Description = "Create and build Static C/C++ Library")] + [TestCase ("Console Project", "C/C++", TestName = "TestMiscCCPlusConsoleProject", Description = "Create and build Console C/C++ Project")] + public void RunMiscCPlusPlusTemplatesTest (string templateName, string templateKind) + { + RunMiscTemplatesTest (templateName, templateKind); + } + + [Test] + [TestCase ("Generic Project", "Generic", TestName = "TestMiscGenericProject", Description = "Create and build Generic Project")] + [TestCase ("Packaging project", "Generic", TestName = "TestMiscPackagingProject", Description = "Create and build Packaging Project")] + public void RunMiscTemplatesTest (string templateName, string templateKind) { var templateOptions = new TemplateSelectionOptions { @@ -48,7 +55,8 @@ namespace UserInterfaceTests TemplateKindRoot = templateKind, TemplateKind = templateName }; - CreateBuildProject (templateOptions, EmptyAction); + CreateBuildProject (templateOptions, () => Ide.WaitForIdeIdle ()); + IsTemplateSelected (templateOptions); } } } diff --git a/main/tests/UserInterfaceTests/TestService.cs b/main/tests/UserInterfaceTests/TestService.cs index ba24222dee..a66d0c374c 100644 --- a/main/tests/UserInterfaceTests/TestService.cs +++ b/main/tests/UserInterfaceTests/TestService.cs @@ -38,8 +38,6 @@ namespace UserInterfaceTests { Session = new AutoTestClientSession (); - //TODO: support for testing the installed app - Session.StartApplication (file: monoDevelopBinPath, environment: new Dictionary<string,string> { { "MONODEVELOP_TEST_PROFILE", profilePath ?? Util.CreateTmpDir ("profile") } }); diff --git a/main/tests/UserInterfaceTests/UITestBase.cs b/main/tests/UserInterfaceTests/UITestBase.cs index f446223ff0..5ca0da478d 100644 --- a/main/tests/UserInterfaceTests/UITestBase.cs +++ b/main/tests/UserInterfaceTests/UITestBase.cs @@ -30,6 +30,9 @@ using MonoDevelop.Components.AutoTest; using System; using System.Collections.Generic; using Newtonsoft.Json; +using System.Linq; +using MonoDevelop.Core.Logging; +using MonoDevelop.Core; namespace UserInterfaceTests { @@ -38,12 +41,13 @@ namespace UserInterfaceTests { string currentWorkingDirectory; string testResultFolder; - string memoryUsageFolder; string currentTestResultFolder; + string currentTestResultScreenshotFolder; - int testScreenshotIndex; + int testScreenshotIndex, reproStepIndex; protected readonly List<string> FoldersToClean = new List<string> (); + protected FileLogger Logger; public AutoTestClientSession Session { get { return TestService.Session; } @@ -55,7 +59,23 @@ namespace UserInterfaceTests protected UITestBase (string mdBinPath) { - MonoDevelopBinPath = mdBinPath; + var installedXS = Environment.GetEnvironmentVariable ("USE_INSTALLED_XS"); + if (!string.IsNullOrWhiteSpace(installedXS)) { + if (Platform.IsMac) + installedXS = Path.Combine(installedXS, "Contents/MacOS/XamarinStudio"); + else if (Platform.IsWindows) + installedXS = Path.Combine(installedXS, @"bin\XamarinStudio.exe"); + } + + if (File.Exists (installedXS)) { + MonoDevelopBinPath = installedXS; + Console.WriteLine ("[UITEST] Using installed Xamarin Studio from this location: " + installedXS); + } + else { + Console.WriteLine ("[UITEST] Installed Xamarin Studio not found. Falling back to default behavior."); + MonoDevelopBinPath = mdBinPath; + } + currentWorkingDirectory = Directory.GetCurrentDirectory (); } @@ -63,58 +83,143 @@ namespace UserInterfaceTests public virtual void FixtureSetup () { testResultFolder = Path.Combine (currentWorkingDirectory, "TestResults"); - memoryUsageFolder = Path.Combine (testResultFolder, "MemoryUsage"); - if (!Directory.Exists (memoryUsageFolder)) - Directory.CreateDirectory (memoryUsageFolder); } [SetUp] public virtual void SetUp () { - SetupTestResultFolder (TestContext.CurrentContext.Test.FullName); - var currentXSIdeLog = Path.Combine (currentTestResultFolder,string.Format ("{0}.Ide.log", TestContext.CurrentContext.Test.FullName) ); - Environment.SetEnvironmentVariable ("MONODEVELOP_LOG_FILE", currentXSIdeLog); - Environment.SetEnvironmentVariable ("MONODEVELOP_FILE_LOG_LEVEL", "UpToInfo"); + SetupTestResultFolder (); + SetupTestLogger (); + SetupScreenshotsFolder (); + SetupIdeLogFolder (); var mdProfile = Util.CreateTmpDir (); TestService.StartSession (MonoDevelopBinPath, mdProfile); TestService.Session.DebugObject = new UITestDebug (); FoldersToClean.Add (mdProfile); + + Session.WaitForElement (IdeQuery.DefaultWorkbench); + TakeScreenShot ("Application-Started"); + CloseIfXamarinUpdateOpen (); + TakeScreenShot ("Application-Ready"); } [TearDown] public virtual void Teardown () { - File.WriteAllText (Path.Combine (memoryUsageFolder, TestContext.CurrentContext.Test.FullName), - JsonConvert.SerializeObject (Session.MemoryStats, Formatting.Indented)); + try { + bool isInconclusive = false; + var testStatus = TestContext.CurrentContext.Result.Status; + if (testStatus != TestStatus.Passed) { + try { + var updateOpened = Session.Query (IdeQuery.XamarinUpdate); + if (updateOpened != null && updateOpened.Any ()) + isInconclusive = true; + TakeScreenShot (string.Format ("{0}-Test-Failed", TestContext.CurrentContext.Test.Name)); + } catch (Exception e) { + Session.DebugObject.Debug ("Final Screenshot failed"); + Session.DebugObject.Debug (e.ToString ()); + } + } + + File.WriteAllText (Path.Combine (currentTestResultFolder, "MemoryUsage.json"), + JsonConvert.SerializeObject (Session.MemoryStats, Formatting.Indented)); - Ide.CloseAll (); - TestService.EndSession (); + Ide.CloseAll (); + TestService.EndSession (); - OnCleanUp (); - if (TestContext.CurrentContext.Result.Status == TestStatus.Passed) { - if (Directory.Exists (currentTestResultFolder)) - Directory.Delete (currentTestResultFolder, true); + ValidateIdeLogMessages (); + + OnCleanUp (); + if (testStatus == TestStatus.Passed) { + if (Directory.Exists (currentTestResultScreenshotFolder)) + Directory.Delete (currentTestResultScreenshotFolder, true); + } + + if (isInconclusive) + Assert.Inconclusive ("Xamarin Update is blocking the application focus"); + } finally { + LoggingService.RemoveLogger (Logger.Name); + Logger.Dispose (); } } - void SetupTestResultFolder (string testName) + static void ValidateIdeLogMessages () { - testScreenshotIndex = 1; - currentTestResultFolder = Path.Combine (testResultFolder, testName); + LogMessageValidator.Validate (Environment.GetEnvironmentVariable ("MONODEVELOP_LOG_FILE")); + } + + protected void CloseIfXamarinUpdateOpen () + { + try { + Session.WaitForElement (IdeQuery.XamarinUpdate, 10 * 1000); + TakeScreenShot ("Xamarin-Update-Opened"); + Session.ClickElement (c => IdeQuery.XamarinUpdate (c).Children ().Button ().Text ("Close")); + } + catch (TimeoutException) { + TestService.Session.DebugObject.Debug ("Xamarin Update did not open"); + } + } + + void SetupTestResultFolder () + { + currentTestResultFolder = Path.Combine (testResultFolder, TestContext.CurrentContext.Test.Name); if (Directory.Exists (currentTestResultFolder)) Directory.Delete (currentTestResultFolder, true); Directory.CreateDirectory (currentTestResultFolder); } - protected void TakeScreenShot (string stepName) + void SetupTestLogger () + { + reproStepIndex = 0; + var currentTestLog = Path.Combine (currentTestResultFolder, string.Format ("{0}.Test.log.txt", TestContext.CurrentContext.Test.Name.ToPathSafeString ())); + Logger = new FileLogger (currentTestLog) { + Name = TestContext.CurrentContext.Test.Name, + EnabledLevel = EnabledLoggingLevel.All, + }; + LoggingService.AddLogger (Logger); + } + + void SetupScreenshotsFolder () { - stepName = string.Format ("{0:D3}-{1}", testScreenshotIndex++, stepName); - var screenshotPath = Path.Combine (currentTestResultFolder, stepName) + ".png"; + testScreenshotIndex = 1; + currentTestResultScreenshotFolder = Path.Combine (currentTestResultFolder, "Screenshots"); + if (Directory.Exists (currentTestResultScreenshotFolder)) + Directory.Delete (currentTestResultScreenshotFolder, true); + Directory.CreateDirectory (currentTestResultScreenshotFolder); + } + + void SetupIdeLogFolder () + { + var currentXSIdeLog = Path.Combine (currentTestResultFolder, string.Format ("{0}.Ide.log", TestContext.CurrentContext.Test.Name.ToPathSafeString ())); + Environment.SetEnvironmentVariable ("MONODEVELOP_LOG_FILE", currentXSIdeLog); + Environment.SetEnvironmentVariable ("MONODEVELOP_FILE_LOG_LEVEL", "UpToInfo"); + } + + public void TakeScreenShot (string stepName) + { + stepName = string.Format ("{0:D3}-{1}", testScreenshotIndex++, stepName).ToPathSafeString (); + var screenshotPath = Path.Combine (currentTestResultScreenshotFolder, stepName) + ".png"; Session.TakeScreenshot (screenshotPath); } + public void ReproStep (string stepDescription, params object[] info) + { + reproStepIndex++; + stepDescription = string.Format ("@Repro-Step-{0:D2}: {1}", reproStepIndex, stepDescription); + LoggingService.LogInfo (stepDescription); + foreach (var obj in info) { + if (obj != null) + LoggingService.LogInfo (string.Format("@Repro-Info-{0:D2}: {1}", reproStepIndex, obj.ToString ())); + } + } + + public void ReproFailedStep (string expected, string actual, params object [] info) + { + ReproStep (string.Format ("Expected: {0}\nActual: {1}", expected, actual), info); + } + protected virtual void OnCleanUp () { foreach (var folder in FoldersToClean) { @@ -122,7 +227,9 @@ namespace UserInterfaceTests if (folder != null && Directory.Exists (folder)) Directory.Delete (folder, true); } catch (IOException e) { - Console.WriteLine ("Cleanup failed\n" +e.ToString ()); + TestService.Session.DebugObject.Debug ("Cleanup failed\n" +e); + } catch (UnauthorizedAccessException e) { + TestService.Session.DebugObject.Debug (string.Format ("Unable to clean directory: {0}\n", folder) + e); } } } @@ -133,6 +240,7 @@ namespace UserInterfaceTests var dirObj = Session.GetGlobalValue ("MonoDevelop.Ide.IdeApp.ProjectOperations.CurrentSelectedSolution.RootFolder.BaseDirectory"); return dirObj != null ? dirObj.ToString () : null; } catch (Exception) { + TestService.Session.DebugObject.Debug ("GetSolutionDirectory () returns null"); return null; } } diff --git a/main/tests/UserInterfaceTests/UserInterfaceTests.csproj b/main/tests/UserInterfaceTests/UserInterfaceTests.csproj index 42facba4c7..63d7d1963f 100644 --- a/main/tests/UserInterfaceTests/UserInterfaceTests.csproj +++ b/main/tests/UserInterfaceTests/UserInterfaceTests.csproj @@ -8,7 +8,7 @@ <ProjectGuid>{07F55155-51A8-4072-9F80-FA473666F086}</ProjectGuid> <OutputType>Library</OutputType> <RootNamespace>UserInterfaceTests</RootNamespace> - <AssemblyName>UserInterfaceTests</AssemblyName> + <AssemblyName>MonoDevelop.UITests</AssemblyName> <TestRunnerCommand>..\..\build\bin\mdtool.exe</TestRunnerCommand> <TestRunnerArgs>run-md-tests</TestRunnerArgs> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> @@ -30,6 +30,20 @@ <WarningLevel>4</WarningLevel> <DebugSymbols>true</DebugSymbols> </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMac|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <Optimize>false</Optimize> + <OutputPath>..\..\build\tests</OutputPath> + <DefineConstants>DEBUG,MAC</DefineConstants> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMac|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>..\..\build\tests</OutputPath> + <WarningLevel>4</WarningLevel> + </PropertyGroup> <ItemGroup> <Reference Include="System" /> <Reference Include="System.Core" /> @@ -53,6 +67,7 @@ <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" /> <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" /> <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" /> + <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> <Compile Include="UITestBase.cs" /> @@ -66,10 +81,8 @@ <Compile Include="TemplateTests\ASPNETTemplateTests.cs" /> <Compile Include="TemplateTests\DotNetTemplatesTest.cs" /> <Compile Include="TemplateTests\MiscTemplatesTest.cs" /> - <Compile Include="VersionControlTests\GitTests.cs" /> <Compile Include="VersionControlTests\VCSBase.cs" /> <Compile Include="VersionControlTests\SvnTests.cs" /> - <Compile Include="VersionControlTests\GitRepositoryConfigurationTests.cs" /> <Compile Include="DialogTests\NewProjectDialogTests.cs" /> <Compile Include="IdeQuery.cs" /> <Compile Include="Controllers\NewFileController.cs" /> @@ -77,6 +90,17 @@ <Compile Include="Controllers\SolutionExplorerController.cs" /> <Compile Include="Controllers\NuGetController.cs" /> <Compile Include="DialogTests\NuGetDialogTests.cs" /> + <Compile Include="Exceptions\TemplateSelectionException.cs" /> + <Compile Include="Exceptions\CreateProjectException.cs" /> + <Compile Include="Workbench.cs" /> + <Compile Include="VersionControlTests\Git\GitBase.cs" /> + <Compile Include="VersionControlTests\Git\GitRepositoryConfigurationTests.cs" /> + <Compile Include="VersionControlTests\Git\GitStashManagerTests.cs" /> + <Compile Include="VersionControlTests\Git\GitTests.cs" /> + <Compile Include="Controllers\NuGetOptions.cs" /> + <Compile Include="Controllers\OptionsController.cs" /> + <Compile Include="Exceptions\NuGetException.cs" /> + <Compile Include="LogMessageValidator.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> @@ -107,10 +131,12 @@ <NuGet>$(SolutionDir)\external\nuget-binary\NuGet.exe</NuGet> <NuGet Condition="$(OS)=='Unix'">mono $(NuGet)</NuGet> </PropertyGroup> - <Exec Command="$(NuGet) restore -SolutionDirectory $(SolutionDir)" /> + <Exec Condition="Exists('$(SolutionDir)\..\.git')" Command="$(NuGet) restore -SolutionDirectory $(SolutionDir)" /> </Target> <ItemGroup> <Folder Include="DialogTests\" /> <Folder Include="Controllers\" /> + <Folder Include="Exceptions\" /> + <Folder Include="VersionControlTests\Git\" /> </ItemGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/main/tests/UserInterfaceTests/Util.cs b/main/tests/UserInterfaceTests/Util.cs index a983c16adb..8658e5f179 100644 --- a/main/tests/UserInterfaceTests/Util.cs +++ b/main/tests/UserInterfaceTests/Util.cs @@ -28,11 +28,29 @@ using System; using System.IO; using MonoDevelop.Core; using System.Reflection; +using System.Linq; namespace UserInterfaceTests { public static class Util { + public static void PrintData (this object data) + { + if (data != null) + TestService.Session.DebugObject.Debug (data.ToString ()); + } + + public static string ToPathSafeString (this string str, char replaceWith = '-') + { + var invalids = Path.GetInvalidFileNameChars ().Concat (Path.GetInvalidPathChars ()).Distinct ().ToArray (); + return new string (str.Select (c => invalids.Contains (c) ? replaceWith : c).ToArray ()); + } + + public static string ToBoldText (this string str) + { + return str != null ? string.Format ("<b>{0}</b>", str) : null; + } + public static FilePath CreateTmpDir (string hint = null) { var cwd = new FileInfo (Assembly.GetExecutingAssembly ().Location).DirectoryName; @@ -57,5 +75,15 @@ namespace UserInterfaceTests return Ide.EmptyAction; } } + + public static Action<string> GetNonNullAction (Action<string> action) + { + return action ?? delegate { }; + } + + public static string StripBold (this string value) + { + return value != null ? value.Replace ("<b>", string.Empty).Replace ("</b>", string.Empty) : null; + } } } diff --git a/main/tests/UserInterfaceTests/VersionControlTests/Git/GitBase.cs b/main/tests/UserInterfaceTests/VersionControlTests/Git/GitBase.cs new file mode 100644 index 0000000000..293015c5f9 --- /dev/null +++ b/main/tests/UserInterfaceTests/VersionControlTests/Git/GitBase.cs @@ -0,0 +1,478 @@ +// +// GitBase.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using MonoDevelop.Components.AutoTest; +using NUnit.Framework; + +namespace UserInterfaceTests +{ + public abstract class GitBase : VCSBase + { + static string notString = "not"; + + #region Git Repository Configuration + + #region Remotes + + Func<AppQuery, AppQuery> remoteTreeName = c => c.TreeView ().Marked ("treeRemotes").Model ("storeRemotes__Name"); + Func<AppQuery, AppQuery> remoteTreeUrl = c => c.TreeView ().Marked ("treeRemotes").Model ("storeRemotes__Url"); + Func<AppQuery, AppQuery> remoteTreeFullName = c => c.TreeView ().Marked ("treeRemotes").Model ("storeRemotes__FullName"); + + protected void AssertRemotesButtonSensitivity (bool editSensitivity, bool removeSensitivity, bool trackSensitivity, bool fetchSensitivity) + { + AssertButtonSensitivity ("Add", true); + AssertButtonSensitivity ("Edit", editSensitivity); + AssertButtonSensitivity ("Remove", removeSensitivity); + AssertButtonSensitivity ("Track in Local Branch", trackSensitivity); + AssertButtonSensitivity ("Fetch", fetchSensitivity); + } + + protected void SelectRemote (string remoteName, string remoteUrl = null) + { + ReproStep (string.Format ("Select a remote named '{0}' {1}", remoteName, + remoteUrl != null ? string.Format (" and Remote URL '{0}'", remoteUrl) : string.Empty)); + Session.WaitForElement (c => remoteTreeName (c).Contains (remoteName)); + + try { + Assert.IsTrue (Session.SelectElement (c => remoteTreeName (c).Contains (remoteName))); + } catch (AssertionException) { + ReproFailedStep (string.Format ("Remote Name '{0}' exists", remoteName), string.Format ("Remote Name '{0}' does not exists", remoteName)); + throw; + } + if (remoteUrl != null) { + try { + Assert.IsTrue (Session.SelectElement (c => remoteTreeUrl (c).Contains (remoteUrl))); + } catch (AssertionException) { + ReproFailedStep (string.Format ("Remote URL '{0}' with Name '{1}' exists", remoteUrl, remoteName), + string.Format ("Remote URL '{0}' with Name '{1}' does not exist", remoteUrl, remoteName)); + throw; + } + } + TakeScreenShot (string.Format ("{0}-Remote-Selected", remoteName)); + } + + protected void EditRemote (string newRemoteName, string remoteUrl, string remotePushUrl = null) + { + ReproStep ("Click on Edit"); + AddEditRemote ("buttonEditRemote", newRemoteName, remoteUrl, remotePushUrl); + } + + protected void AddRemote (string newRemoteName, string remoteUrl, string remotePushUrl = null) + { + ReproStep ("Click on Add"); + AddEditRemote ("buttonAddRemote", newRemoteName, remoteUrl, remotePushUrl); + } + + protected void FetchRemoteBranch (string remoteName) + { + SelectRemote (remoteName); + + Assert.IsEmpty (Session.Query (c => remoteTreeFullName (c).Contains (remoteName+"/"))); + Assert.IsTrue (Session.ClickElement (c => IdeQuery.GitConfigurationDialog (c).Children ().Button ().Text ("Fetch"))); + TakeScreenShot ("Fetch-Remote"); + + SelectRemoteBranch (remoteName); + } + + protected void SelectRemoteBranch (string remoteName, string remoteBranchName = null) + { + Session.ClickElement (c => remoteTreeName (c).Contains (remoteName)); + Assert.IsNotEmpty (Session.Query (c => remoteTreeFullName (c).Contains (remoteName+"/"+remoteBranchName))); + + var expected = string.Format ("Select the Remote with Name '{0}' and Remote Branch Name '{1}'", remoteName, remoteBranchName); + try { + ReproStep (expected); + Assert.IsTrue (Session.SelectElement (c => remoteTreeFullName (c).Contains (remoteName + "/" + remoteBranchName).Index (0))); + } catch (AssertionException) { + ReproFailedStep (expected, "Could not "+expected); + throw; + } + TakeScreenShot (string.Format ("{0}-Remote-Branch-Selected", remoteBranchName ?? "First")); + } + + void AddEditRemote (string buttonName, string newRemoteName, string remoteUrl, string remotePushUrl) + { + Assert.IsNotEmpty (Session.Query (c => IdeQuery.GitConfigurationDialog (c).Children ().Button ().Marked (buttonName))); + Session.ClickElement (c => IdeQuery.GitConfigurationDialog (c).Children ().Button ().Marked (buttonName), false); + Session.WaitForElement (IdeQuery.EditRemoteDialog); + + ReproStep (string.Format ("Enter Remote name as '{0}'", newRemoteName)); + Func<AppQuery, AppQuery> EditRemoteDialogChildren = c => IdeQuery.EditRemoteDialog (c).Children (); + Assert.IsTrue (Session.EnterText (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryName"), newRemoteName)); + Session.WaitForElement (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryName").Text (newRemoteName)); + + ReproStep (string.Format ("Enter Remote URL as '{0}'", remoteUrl)); + Assert.IsTrue (Session.EnterText (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryUrl"), remoteUrl)); + Session.WaitForElement (c => EditRemoteDialogChildren (c).Marked ("entryUrl").Text (remoteUrl)); + + ReproStep (string.Format ("Enter Remote Push URL as '{0}'", remotePushUrl ?? remoteUrl)); + Assert.IsTrue (Session.EnterText (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryPushUrl"), remotePushUrl ?? remoteUrl)); + Session.WaitForElement (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryPushUrl").Text (remotePushUrl ?? remoteUrl)); + TakeScreenShot ("Remote-Details-Filled"); + + ReproStep ("Click on OK"); + Assert.IsTrue (Session.ClickElement (c => EditRemoteDialogChildren (c).Button ().Marked ("buttonOk"))); + Session.WaitForNoElement (IdeQuery.EditRemoteDialog); + Session.WaitForElement (IdeQuery.GitConfigurationDialog); + TakeScreenShot ("Remote-Edit-Dialog-Closed"); + } + + protected void DeleteRemote (string remoteName) + { + Session.WaitForElement (c => remoteTreeName (c).Contains (remoteName)); + ReproStep ("Click on Remove"); + Session.ClickElement (c => IdeQuery.GitConfigurationDialog(c).Children ().Button ().Text ("Remove"), false); + TakeScreenShot (string.Format ("Remove-Remote-{0}", remoteName)); + + ReproStep ("When prompted to confirm, click Delete"); + Ide.ClickButtonAlertDialog ("Delete"); + Session.WaitForElement (IdeQuery.GitConfigurationDialog); + } + + #endregion + + #region Tags + + Func<AppQuery, AppQuery> tagTreeName = c => c.TreeView ().Marked ("listTags").Model ("storeTags__Name"); + + protected void AssertTagsButtonSensitivity (bool pushSensitivity, bool deleteSensitivity) + { + AssertButtonSensitivity ("New", true); + AssertButtonSensitivity ("Push", pushSensitivity); + AssertButtonSensitivity ("Delete", deleteSensitivity); + } + + protected void SelectTag (string tagName) + { + WaitForElement (c => tagTreeName (c).Text (tagName), + string.Format ("Tag '{0}' should be available", tagName), + string.Format ("Tag '{0}' it not available", tagName)); + try { + Assert.IsTrue (Session.SelectElement (c => tagTreeName (c).Text (tagName)), "Failed to select tag: " + tagName); + } catch (AssertionException) { + ReproFailedStep (string.Format ("Tag '{0}' should be selected", tagName), + string.Format ("Tag '{0}' cannot be selected", tagName)); + throw; + } + TakeScreenShot (string.Format ("{0}-Tag-Selected", tagName)); + } + + protected void DeleteTag (string tagName) + { + SelectTag (tagName); + ReproStep ("Click Delete"); + try { + Assert.IsTrue ((Session.ClickElement (c => IdeQuery.GitConfigurationDialog (c).Children ().Button ().Marked ("buttonRemoveTag")))); + } catch (AssertionException) { + ReproFailedStep (string.Format ("Tag '{0}' should be removed", tagName), string.Format ("Tag '{0}' could not be removed", tagName)); + throw; + } + Session.WaitForNoElement (c => tagTreeName (c).Text (tagName)); + } + + protected void AddNewTag (string tagName, string tagMessage = null, string commitMsg = null) + { + ReproStep ("Click on New"); + Session.ClickElement (c => IdeQuery.GitConfigurationDialog (c).Children ().Button ().Marked ("buttonAddTag"), false); + + ReproStep ("Wait for 'Select a Revision' dialog to open"); + try { + Session.WaitForElement (c => c.Window ().Marked ("Select a revision")); + } catch (AssertionException) { + ReproFailedStep ("'Select a Revision' dialog should open", "'Select a Revision' dialog did not open"); + throw; + } + + ReproStep ("Enter the Tag Name"); + Session.EnterText (c => c.Window ().Marked ("Select a revision").Children ().Textfield ().Index (0), tagName); + Session.WaitForElement (c => c.Window ().Marked ("Select a revision").Children ().Textfield ().Index (0).Text (tagName)); + TakeScreenShot ("Tag-Name-Entered"); + + if (!string.IsNullOrEmpty (tagMessage)) { + ReproStep ("Enter a Tag Message"); + Session.EnterText (c => c.Window ().Marked ("Select a revision").Children ().Textfield ().Index (1), tagMessage); + Session.WaitForElement (c => c.Window ().Marked ("Select a revision").Children ().Textfield ().Index (1).Text (tagMessage)); + TakeScreenShot ("Tag-Message-Entered"); + } + + Func<AppQuery, AppQuery> revisionsTreeView = c => c.Window ().Marked ("Select a revision").Children ().TreeView ().Index (0).Model ().Children (); + if (!string.IsNullOrEmpty (commitMsg)) { + ReproStep (string.Format ("Select the commit with message '{0}'", commitMsg)); + Session.SelectElement (c => revisionsTreeView (c).Text (commitMsg)); + } else { + ReproStep ("Select the first commit"); + Session.SelectElement (c => revisionsTreeView (c).Index (0)); + } + TakeScreenShot ("Commit-Message-Selected"); + + ReproStep ("Click OK"); + Session.ClickElement (c => c.Window ().Marked ("Select a revision").Children ().Button ().Text ("Ok")); + try { + Session.WaitForElement (IdeQuery.GitConfigurationDialog); + TakeScreenShot ("Git-User-Not-Configured"); + EnterGitUserConfig ("John Doe", "john.doe@example.com"); + } catch (TimeoutException e) { } + Session.WaitForElement (c => IdeQuery.GitConfigurationDialog (c)); + TakeScreenShot ("Ok-Clicked"); + } + + #endregion + + #region Branches + + Func<AppQuery, AppQuery> branchDisplayName = c => c.TreeView ().Marked ("listBranches").Model ("storeBranches__DisplayName"); + + protected void AssertBranchesButtonSensitivity (bool editSensitivity, bool deleteSensitivity, bool switchSensitivity) + { + AssertButtonSensitivity ("New", true); + AssertButtonSensitivity ("Edit", editSensitivity); + AssertButtonSensitivity ("Delete", deleteSensitivity); + AssertButtonSensitivity ("Switch to Branch", switchSensitivity); + } + + protected void CreateNewBranch (string newBranchName) + { + ReproStep ("Click New"); + CreateEditBranch ("buttonAddBranch", newBranchName); + } + + protected void EditBranch (string oldBranchName, string newBranchName) + { + SelectBranch (oldBranchName); + ReproStep ("Click Edit"); + CreateEditBranch ("buttonEditBranch", newBranchName); + } + + protected void CreateEditBranch (string buttonName, string newBranchName) + { + Session.ClickElement (c => IdeQuery.GitConfigurationDialog(c).Children ().Button ().Marked (buttonName), false); + + ReproStep ("Wait for Branch Properties dialog"); + WaitForElement (IdeQuery.EditBranchDialog, "Branch Properties dialog opens", "Branch Properties dialog does not open"); + TakeScreenShot ("Edit-Branch-Dialog-Opened"); + + EnterBranchName (newBranchName); + Session.WaitForElement (IdeQuery.GitConfigurationDialog); + TakeScreenShot ("Edit-Branch-Dialog-Opened-Closed"); + } + + protected void EnterBranchName (string newBranchName) + { + ReproStep ("Enter branch name"); + Session.EnterText (c => IdeQuery.EditBranchDialog (c).Children ().Textfield ().Marked ("entryName"), newBranchName); + Session.WaitForElement (c => IdeQuery.EditBranchDialog (c).Children ().Textfield ().Marked ("entryName").Text (newBranchName)); + TakeScreenShot ("Branch-Name-Entered"); + + ReproStep ("Click OK"); + Assert.IsTrue (Session.ClickElement (c => IdeQuery.EditBranchDialog (c).Children ().Button ().Marked ("buttonOk"))); + } + + protected void SwitchToBranch (string branchName) + { + SelectBranch (branchName); + TakeScreenShot (string.Format ("{0}-Branch-Selected", branchName)); + + ReproStep ("Click on 'Switch to Branch'"); + Session.ClickElement (c => IdeQuery.GitConfigurationDialog(c).Children ().Button ().Text ("Switch to Branch"), false); + CheckIfNameEmailNeeded (); + CheckIfUserConflict (); + ReproStep ("Check if the selected branch is bold"); + try { + Assert.IsTrue (IsBranchSwitched (branchName)); + } catch (AssertionException) { + ReproFailedStep ("The selected branch should be bold", "The selected branch is not bold"); + throw; + } + TakeScreenShot (string.Format ("Switched-To-{0}", branchName)); + } + + protected void SwitchTab (string tabName) + { + ReproStep (string.Format ("Select the '{0}' tab", tabName)); + try { + Assert.IsTrue (Session.SelectElement (c => IdeQuery.GitConfigurationDialog (c).Children ().Notebook ().Marked ("notebook1").Text (tabName))); + } catch (AssertionException) { + ReproFailedStep (string.Format ("Tab '{0}' is selected", tabName), string.Format ("Tab '{0}' is not selected", tabName)); + throw; + } + TakeScreenShot (string.Format ("Tab-Changed-{0}", GenerateProjectName (tabName))); + } + + protected void SelectBranch (string branchName) + { + ReproStep (string.Format ("Select the '{0}' branch", branchName)); + try { + Assert.IsTrue (Session.SelectElement (c => branchDisplayName (c).Contains (branchName))); + } catch (AssertionException) { + ReproFailedStep (string.Format ("Branch '{0}' is selected", branchName), string.Format ("Branch '{0}' is not selected", branchName)); + throw; + } + TakeScreenShot (string.Format ("Selected-Branch-{0}", branchName.ToPathSafeString ())); + } + + protected void DeleteBranch (string branchName) + { + SelectBranch (branchName); + ReproStep ("Press Delete"); + Session.ClickElement (c => IdeQuery.GitConfigurationDialog (c).Children ().Button ().Text ("Delete"), false); + TakeScreenShot (string.Format ("Delete-Branch-{0}", branchName)); + ReproStep ("If prompted for confirmation, press Delete"); + Ide.ClickButtonAlertDialog ("Delete"); + Session.WaitForElement (IdeQuery.GitConfigurationDialog); + } + + protected bool IsBranchSwitched (string branchName) + { + try { + WaitForElement (c => branchDisplayName (c).Text ("<b>" + branchName + "</b>"), + string.Format ("Branch '{0}' is checked out", branchName), + string.Format ("Branch '{0}' is not checked out", branchName)); + return true; + } catch (TimeoutException) { + return false; + } + } + + #endregion + + protected void OpenRepositoryConfiguration (string selectTab = null) + { + ReproStep ("Click Version Control > Manage Branches and Remotes"); + Session.ExecuteCommand (MonoDevelop.VersionControl.Git.Commands.ManageBranches); + + WaitForElement (IdeQuery.GitConfigurationDialog, + "Git Repository Configuration Dialog should open", + "Git Repository Configuration Dialog did not open"); + TakeScreenShot ("Repository-Configuration-Opened"); + + if (selectTab != null) + SwitchTab (selectTab); + } + + protected void CloseRepositoryConfiguration () + { + ReproStep ("Click on Close button of Git Repository Configuration Dialog"); + Session.ClickElement (c => IdeQuery.GitConfigurationDialog(c).Children ().Button ().Marked ("buttonOk")); + TakeScreenShot ("Git-Repository-Configuration-Closed"); + Session.WaitForNoElement (IdeQuery.GitConfigurationDialog); + } + + protected void AssertButtonSensitivity (string buttonLabel, bool sensitivity) + { + var expected = string.Format ("{0} button is {1} enabled", buttonLabel, !sensitivity ? notString : string.Empty); + var actual = string.Format ("{0} button is {1} enabled", buttonLabel, sensitivity ? notString : string.Empty); + try { + Assert.IsNotEmpty (Session.Query (c => c.Button ().Text (buttonLabel).Sensitivity (sensitivity)), actual); + } catch (AssertionException) { + ReproFailedStep (expected, actual); + throw; + } + } + + #endregion + + #region Stash Manager + + protected Func<AppQuery, AppQuery> StashEntries = c => c.Window ().Marked ( + "Stash Manager").Children ().TreeView ().Marked ("list").Model ().Children (); + + protected void OpenStashManager () + { + ReproStep ("Click on Version Control > Manage Stashes"); + Session.ExecuteCommand ("MonoDevelop.VersionControl.Git.Commands.ManageStashes"); + WaitForElement (c => c.Window ().Marked ("Stash Manager"), "Stash Manager dialog should open", "Stash Manager dialog did not open"); + TakeScreenShot ("StashManager-Opened"); + } + + protected void CloseStashManager () + { + ReproStep ("On Stash Manager, click Close button"); + Session.ClickElement (c => c.Window ().Marked ("Stash Manager").Children ().Text ("Close")); + Session.WaitForElement (IdeQuery.TextArea); + TakeScreenShot ("StashManager-Closed"); + } + + protected void SelectStashEntry (int index = 0) + { + ReproStep ("Select the stash entry #{0}", index+1); + WaitForElement (c => StashEntries (c).Index (index), "Select stash entry: "+index+1, "Could not select that stash entry"); + Session.SelectElement (c => StashEntries (c).Index (index)); + } + + protected void RemoveStash (int index) + { + SelectStashEntry (index); + TakeScreenShot ("About-To-Click-Remove"); + try { + ReproStep ("Click on Remove"); + Assert.IsTrue (Session.ClickElement (c => c.Window ().Marked ("Stash Manager").Children ().Button ().Text ("Remove"))); + } catch (AssertionException) { + ReproFailedStep ("Stash should be removed", "Stash failed to remove"); + throw; + } + Session.WaitForElement (c => c.Window ().Marked ("Stash Manager")); + } + + protected void ApplyAndRemoveStash (int index) + { + SelectStashEntry (index); + TakeScreenShot ("About-To-Click-Apply-and-Remove"); + try { + ReproStep ("Click on 'Apply and Remove'"); + Assert.IsTrue (Session.ClickElement (c => c.Window ().Marked ("Stash Manager").Children ().Button ().Text ("Apply and Remove"))); + } catch (AssertionException) { + ReproFailedStep ("Stash should be applied and removed from the list", "Stash failed to applied and removed from the list"); + throw; + } + } + + protected void ApplyStash (int index) + { + SelectStashEntry (index); + TakeScreenShot ("About-To-Click-Apply"); + try { + ReproStep ("Click on Apply"); + Assert.IsTrue (Session.ClickElement (c => c.Window ().Marked ("Stash Manager").Children ().Button ().Text ("Apply"))); + } catch (AssertionException) { + ReproFailedStep ("Stash should be applied", "Stash failed to apply"); + throw; + } + } + + protected void ComvertToBranch (int index, string branchName) + { + SelectStashEntry (index); + TakeScreenShot ("About-To-Click-Convert-To-Branch"); + ReproStep ("Click on 'Convert to Branch'"); + Session.ClickElement (c => c.Window ().Marked ("Stash Manager").Children ().Button ().Text ("Convert to Branch"), false); + EnterBranchName (branchName); + Ide.WaitForStatusMessage (new [] { "Stash successfully applied" }); + } + + #endregion + } +} + diff --git a/main/tests/UserInterfaceTests/VersionControlTests/Git/GitRepositoryConfigurationTests.cs b/main/tests/UserInterfaceTests/VersionControlTests/Git/GitRepositoryConfigurationTests.cs new file mode 100644 index 0000000000..1c5c9eb52a --- /dev/null +++ b/main/tests/UserInterfaceTests/VersionControlTests/Git/GitRepositoryConfigurationTests.cs @@ -0,0 +1,356 @@ +// +// GitRepositoryConfigurationTests.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System;
+using NUnit.Framework; + +namespace UserInterfaceTests +{ + [TestFixture, Timeout(90000)] + [Category ("GitConfig")] + public class GitRepositoryConfigurationTests : GitBase + { + const string gtkSharpUrl = "https://github.com/mono/gtk-sharp.git"; + const string monoHotdrawUrl = "https://github.com/mono/monocov.git"; + + #region Branch Tab + + [Test] + [Description ("Check that Edit, Switch, Switch to Branch are enabled only when a branch is selected")] + public void CheckBranchButtonsSensitivity () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Branches"); + + TakeScreenShot ("Asserting-Edit-Delete-Switch-Button-Disabled"); + AssertBranchesButtonSensitivity (false, false, false); + SelectBranch ("<b>master</b>"); + TakeScreenShot ("Asserting-Edit-Switch-Button-Enabled"); + AssertBranchesButtonSensitivity (true, false, false); + CreateNewBranch ("new-branch"); + SelectBranch ("new-branch"); + TakeScreenShot ("Asserting-Edit-Delete-Switch-Button-Enabled"); + AssertBranchesButtonSensitivity (true, true, true); + + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Create a New Branch")] + public void CreateNewBranchTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration (); + CreateNewBranch ("new-branch"); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Create a New Branch and switch to it")] + public void GitSwitchBranchTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration (); + CreateNewBranch ("new-branch"); + SwitchToBranch ("new-branch"); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Create a New Branch, select it and edit the name and switch to it")] + public void GitEditBranchTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration (); + CreateNewBranch ("new-branch"); + SelectBranch ("new-branch"); + EditBranch ("new-branch", "new-new-branch"); + SwitchToBranch ("new-new-branch"); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Create a new branch, select it and delete it")] + public void GitDeleteBranchTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration (); + CreateNewBranch ("new-branch"); + SelectBranch ("new-branch"); + DeleteBranch ("new-branch"); + + CloseRepositoryConfiguration (); + } + + #endregion + + #region Tag + + [Test] + [Description ("Check that Push and Delete button are enabled only when a tag is selected")] + public void CheckTagButtonsSensitivity () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Tags"); + + TakeScreenShot ("Asserting-Push-Delete-Button-Disabled"); + AssertTagsButtonSensitivity (false, false); + SelectTag ("1.0.10"); + TakeScreenShot ("Asserting-Push-Delete-Button-Enabled"); + AssertTagsButtonSensitivity (true, true); + + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Create a new tag with tag name, tag message and by selecting a specific commit message")] + public void AddTag () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Tags"); + + AddNewTag ("bumped", "bumped tag", "build: Bump mono dependency to 3.2.8"); + SelectTag ("bumped"); + TakeScreenShot ("New-Tag-Selected"); + + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Clone a repo, open Tag tab, select a tag by name and delete it")] + public void DeleteTag () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Tags"); + DeleteTag ("1.0.10"); + CloseRepositoryConfiguration (); + } + + #endregion + + #region Remotes Tab + + [Test] + [Description ("Check that Edit, Remove, Fetch button are enabled only when a remote is selected and 'Track in Local' only when a remote branch is selected")] + public void CheckRemoteButtonsSensitivity () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Remote Sources"); + + TakeScreenShot ("Asserting-Edit-Remove-Track--Fetch-Button-Disabled"); + AssertRemotesButtonSensitivity (false, false, false, false); + SelectRemote ("origin"); + TakeScreenShot ("Asserting-Edit-Switch-Button-Enabled"); + AssertRemotesButtonSensitivity (true, true, false, true); + SelectRemoteBranch ("origin", "master"); + TakeScreenShot ("Asserting-Edit-Switch-Button-Track-Enabled"); + AssertRemotesButtonSensitivity (true, true, true, true); + + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Clone a repo and select a remote")] + public void SelectRemoteTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Remote Sources"); + SelectRemote ("origin"); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Clone a repo, add a new remote and select that added remote")] + public void AddGitRemoteTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + const string newRemoteName = "second"; + const string newRemoteUrl = monoHotdrawUrl; + OpenRepositoryConfiguration ("Remote Sources"); + AddRemote (newRemoteName, newRemoteUrl); + SelectRemote (newRemoteName, newRemoteUrl); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Clone a repo, add a new remote, select it and delete it")] + public void DeleteGitRemoteTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + const string newRemoteName = "second"; + const string newRemoteUrl = monoHotdrawUrl; + OpenRepositoryConfiguration ("Remote Sources"); + AddRemote (newRemoteName, newRemoteUrl); + SelectRemote (newRemoteName, newRemoteUrl); + DeleteRemote (newRemoteName); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Edit only Remote Name, don't edit URL or Push URL")] + public void EditGitRemoteNameTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Remote Sources"); + + const string newRemoteName = "second"; + const string newRemoteUrl = monoHotdrawUrl; + AddRemote (newRemoteName, newRemoteUrl); + SelectRemote (newRemoteName, newRemoteUrl); + + const string updatedRemoteName = "second-origin"; + const string updatedRemoteUrl = monoHotdrawUrl; + EditRemote (updatedRemoteName, updatedRemoteUrl, updatedRemoteUrl); + SelectRemote (updatedRemoteName, updatedRemoteUrl); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Edit only Remote Name and URL, don't edit Push URL")] + public void EditGitRemoteNameAndUrlTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Remote Sources"); + + const string newRemoteName = "second"; + const string newRemoteUrl = monoHotdrawUrl; + AddRemote (newRemoteName, newRemoteUrl); + SelectRemote (newRemoteName, newRemoteUrl); + + const string updatedRemoteName = "second-origin"; + const string updatedRemoteUrl = monoHotdrawUrl; + EditRemote (updatedRemoteName, updatedRemoteUrl, newRemoteUrl); + SelectRemote (updatedRemoteName, updatedRemoteUrl); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Edit only Remote Name and Push URL, don't edit URL")] + public void EditGitRemoteNameAndPushUrlTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Remote Sources"); + + const string newRemoteName = "second"; + const string newRemoteUrl = monoHotdrawUrl; + AddRemote (newRemoteName, newRemoteUrl); + SelectRemote (newRemoteName, newRemoteUrl); + + const string updatedRemoteName = "second-origin"; + const string updatedRemoteUrl = monoHotdrawUrl; + EditRemote (updatedRemoteName, updatedRemoteUrl, monoHotdrawUrl); + SelectRemote (updatedRemoteName, updatedRemoteUrl); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Edit only Remote URL and Push URL, don't edit Name")] + public void EditGitRemoteUrlTest () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + OpenRepositoryConfiguration ("Remote Sources"); + + const string newRemoteName = "second"; + const string newRemoteUrl = monoHotdrawUrl; + AddRemote (newRemoteName, newRemoteUrl); + SelectRemote (newRemoteName, newRemoteUrl); + + const string updatedRemoteUrl = monoHotdrawUrl; + EditRemote (newRemoteName, updatedRemoteUrl, updatedRemoteUrl); + SelectRemote (newRemoteName, updatedRemoteUrl); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Clone a repo, add a new remote and fetch the remote branches for that remote")] + public void FetchRemoteBranches () + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + const string newRemoteName = "second"; + const string newRemoteUrl = monoHotdrawUrl; + OpenRepositoryConfiguration ("Remote Sources"); + AddRemote (newRemoteName, newRemoteUrl); + FetchRemoteBranch (newRemoteName); + CloseRepositoryConfiguration (); + } + + [Test] + [Description ("Clone a repo, add a new remote, fetch the remote branch, chose a branch and track it in local. Select that branch in Branches tab")] + public void TrackRemoteBranchInLocalTest() + { + TestClone (gtkSharpUrl); + Ide.WaitForSolutionCheckedOut (); + + const string newRemoteName = "second"; + const string newRemoteUrl = monoHotdrawUrl; + OpenRepositoryConfiguration ("Remote Sources"); + AddRemote (newRemoteName, newRemoteUrl); + FetchRemoteBranch (newRemoteName); + const string localBranch = "local-branch-random-uitest"; + CreateEditBranch ("buttonTrackRemote", localBranch); + SwitchTab ("Branches"); + SelectBranch (localBranch); + CloseRepositoryConfiguration (); + } + + #endregion + } +} + diff --git a/main/tests/UserInterfaceTests/VersionControlTests/Git/GitStashManagerTests.cs b/main/tests/UserInterfaceTests/VersionControlTests/Git/GitStashManagerTests.cs new file mode 100644 index 0000000000..71736ae25e --- /dev/null +++ b/main/tests/UserInterfaceTests/VersionControlTests/Git/GitStashManagerTests.cs @@ -0,0 +1,119 @@ +// +// GitStashManagerTests.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using NUnit.Framework; +using System; +using MonoDevelop.Ide.Commands; +using MonoDevelop.Components.AutoTest; + +namespace UserInterfaceTests +{ + [TestFixture, Timeout(60000)] + [Category ("Git")] + [Category ("StashManager")] + public class GitStashManagerTests : GitBase + { + [Test] + [Description ("Create a project with git, commit changes. Make changes and stash. Remove stash from Stash Manager")] + public void GitRemoveStashTest () + { + CreateProjectAndCommitAndStash (); + + OpenStashManager (); + RemoveStash (0); + Assert.IsEmpty (Session.Query (StashEntries)); + CloseStashManager (); + } + + [Test] + [Description ("Create a project with git, commit changes. Make changes and stash. Apply and Remove stash from Stash Manager")] + public void GitApplyAndRemoveStashTest () + { + CreateProjectAndCommitAndStash (); + + OpenStashManager (); + ApplyAndRemoveStash (0); + + Session.WaitForElement (IdeQuery.TextArea); + TakeScreenShot ("Stash-Applied"); + OpenStashManager (); + + TakeScreenShot ("Asserting-if-Not-Stash-Present"); + Session.WaitForNoElement (StashEntries); + CloseStashManager (); + } + + [Test] + [Description ("Create a project with git, commit changes. Make changes and stash. Apply stash from Stash Manager")] + public void GitApplyStashTest () + { + CreateProjectAndCommitAndStash (); + + OpenStashManager (); + ApplyStash (0); + OpenStashManager (); + + TakeScreenShot ("Asserting-if-Stash-Still-Present"); + Assert.IsNotEmpty (Session.Query (StashEntries)); + CloseStashManager (); + } + + [Test] + [Description ("Create a project with git, commit changes. Make changes and stash. Convert stash to branch from Stash Manager")] + public void GitStashConvertToBranchTest () + { + CreateProjectAndCommitAndStash (); + + var branchName = "sample-branch"; + OpenStashManager (); + ComvertToBranch (0, branchName); + OpenStashManager (); + TakeScreenShot ("Asserting-if-Stash-Still-Present"); + Assert.IsEmpty (Session.Query (StashEntries)); + CloseStashManager (); + + OpenRepositoryConfiguration ("Branches"); + IsBranchSwitched (branchName); + CloseRepositoryConfiguration (); + } + + void CreateProjectAndCommitAndStash () + { + var templateOptions = new TemplateSelectionOptions { + CategoryRoot = OtherCategoryRoot, + Category = ".NET", + TemplateKindRoot = GeneralKindRoot, + TemplateKind = "Console Project" + }; + GitCreateAndCommit (templateOptions, "First commit"); + var changeDescription = MakeSomeChangesAndSaveAll ("Program.cs"); + TestGitStash (changeDescription); + Session.WaitForElement (IdeQuery.TextArea, 20000); + TakeScreenShot ("After-Stash"); + } + } +} + diff --git a/main/tests/UserInterfaceTests/VersionControlTests/GitTests.cs b/main/tests/UserInterfaceTests/VersionControlTests/Git/GitTests.cs index 471b8a94ff..2bf26bcb52 100644 --- a/main/tests/UserInterfaceTests/VersionControlTests/GitTests.cs +++ b/main/tests/UserInterfaceTests/VersionControlTests/Git/GitTests.cs @@ -30,20 +30,22 @@ using NUnit.Framework; namespace UserInterfaceTests { - [TestFixture] + [TestFixture, Timeout(60000)] [Category ("Git")] + [Category ("GitBase")] public class GitTests : VCSBase { - [Test] - [TestCase ("git@github.com:mono/jurassic.git", TestName = "TestGitSSHClone")] - [TestCase ("https://github.com/mono/jurassic.git", TestName = "TestGitHTTPSClone")] + [Test, Timeout(120000), Category("Smoke")] + [TestCase ("git@github.com:mono/gtk-sharp.git", TestName = "TestGitSSHClone", Description = "Clone Git repo over SSH")] + [TestCase ("https://github.com/mono/gtk-sharp.git", TestName = "TestGitHTTPSClone", Description = "Clone Git repo over HTTPS")] public void TestGitClone (string url) { TestClone (url); - Ide.WaitForSolutionCheckedOut (); + Ide.WaitForIdeIdle (); } - [Test] + [Test, Category("Smoke")] + [Description ("Create a new project with Git and commit the changes")] public void TestCommit () { var templateOptions = new TemplateSelectionOptions { @@ -52,15 +54,11 @@ namespace UserInterfaceTests TemplateKindRoot = GeneralKindRoot, TemplateKind = "Console Project" }; - CreateProject (templateOptions, - new ProjectDetails (templateOptions), - new GitOptions { UseGit = true, UseGitIgnore = true}); - - Session.WaitForElement (IdeQuery.TextArea); - TestCommit ("First commit"); + GitCreateAndCommit (templateOptions, "First commit"); } [Test] + [Description ("Create a new project and try to stash without any changes, it should not be allowed")] public void TestNoChangesStashOperation () { var templateOptions = new TemplateSelectionOptions { @@ -81,6 +79,7 @@ namespace UserInterfaceTests } [Test] + [Description ("Create a new project and try to stash without HEAD commit, it should not be allowed")] public void TestStashWithoutHeadCommit () { var templateOptions = new TemplateSelectionOptions { @@ -98,7 +97,8 @@ namespace UserInterfaceTests TakeScreenShot ("Stash-Window-Doesnt-Show"); } - [Test] + [Test, Category("Smoke")] + [Description ("Create a new project, make a commit, make changes. Stash and Unstash successfully")] public void TestStashAndUnstashSuccessful () { var templateOptions = new TemplateSelectionOptions { @@ -107,23 +107,10 @@ namespace UserInterfaceTests TemplateKindRoot = GeneralKindRoot, TemplateKind = "Console Project" }; - CreateProject (templateOptions, - new ProjectDetails (templateOptions), - new GitOptions { UseGit = true, UseGitIgnore = true }); - - Session.WaitForElement (IdeQuery.TextArea); - TestCommit ("First commit"); - - Session.ExecuteCommand (FileCommands.CloseFile); - Session.WaitForElement (IdeQuery.TextArea); - - Session.ExecuteCommand (TextEditorCommands.InsertNewLine); - TakeScreenShot ("Inserted-Newline-Marked-Dirty"); - Session.ExecuteCommand (FileCommands.SaveAll); - TakeScreenShot ("Inserted-Newline-SaveAll-Called"); - - TestGitStash ("Entered new blank line"); + GitCreateAndCommit (templateOptions, "First commit"); + var changeDescription = MakeSomeChangesAndSaveAll ("Program.cs"); + TestGitStash (changeDescription); Session.WaitForElement (IdeQuery.TextArea); TakeScreenShot ("After-Stash"); diff --git a/main/tests/UserInterfaceTests/VersionControlTests/GitRepositoryConfigurationTests.cs b/main/tests/UserInterfaceTests/VersionControlTests/GitRepositoryConfigurationTests.cs deleted file mode 100644 index 166f0ac4ec..0000000000 --- a/main/tests/UserInterfaceTests/VersionControlTests/GitRepositoryConfigurationTests.cs +++ /dev/null @@ -1,310 +0,0 @@ -// -// GitRepositoryConfigurationTests.cs -// -// Author: -// Manish Sinha <manish.sinha@xamarin.com> -// -// Copyright (c) 2015 Xamarin Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using NUnit.Framework; -using System; -using MonoDevelop.Ide.Commands; -using MonoDevelop.Components.AutoTest; - -namespace UserInterfaceTests -{ - [TestFixture] - [Category ("GitConfig")] - public class GitRepositoryConfigurationTests : GitRepositoryConfigurationBase - { - #region Branch Tab - - [Test] - public void CreateNewBranchTest () - { - TestClone ("git@github.com:mono/jurassic.git"); - Ide.WaitForSolutionCheckedOut (); - - OpenRepositoryConfiguration (); - CreateNewBranch ("new-branch"); - CloseRepositoryConfiguration (); - } - - [Test] - public void GitSwitchBranchTest () - { - TestClone ("git@github.com:mono/jurassic.git"); - Ide.WaitForSolutionCheckedOut (); - - OpenRepositoryConfiguration (); - CreateNewBranch ("new-branch"); - SwitchToBranch ("new-branch"); - CloseRepositoryConfiguration (); - } - - [Test] - public void GitEditBranchTest () - { - TestClone ("git@github.com:mono/jurassic.git"); - Ide.WaitForSolutionCheckedOut (); - - OpenRepositoryConfiguration (); - CreateNewBranch ("new-branch"); - SelectBranch ("new-branch"); - EditBranch ("new-branch", "new-new-branch"); - SwitchToBranch ("new-new-branch"); - CloseRepositoryConfiguration (); - } - - #endregion - - #region Remotes Tab - - [Test] - public void SelectRemoteTest () - { - TestClone ("git@github.com:mono/jurassic.git"); - Ide.WaitForSolutionCheckedOut (); - - OpenRepositoryConfiguration ("Remote Sources"); - SelectRemote ("origin"); - CloseRepositoryConfiguration (); - } - - [Test] - public void AddGitRemoteTest () - { - TestClone ("git@github.com:mono/jurassic.git"); - Ide.WaitForSolutionCheckedOut (); - - const string newRemoteName = "second"; - const string newRemoteUrl = "git@github.com:mono/monohotdraw.git"; - OpenRepositoryConfiguration ("Remote Sources"); - AddRemote (newRemoteName, newRemoteUrl); - SelectRemote (newRemoteName, newRemoteUrl); - CloseRepositoryConfiguration (); - } - - [Test] - [Ignore ("When OK is clicked on EditRemoteDialog, it doesn't update the list")] - public void EditGitRemoteTest () - { - TestClone ("git@github.com:mono/jurassic.git"); - Ide.WaitForSolutionCheckedOut (); - - OpenRepositoryConfiguration ("Remote Sources"); - - const string newRemoteName = "second"; - const string newRemoteUrl = "git@github.com:mono/monohotdraw.git"; - AddRemote (newRemoteName, newRemoteUrl); - SelectRemote (newRemoteName, newRemoteUrl); - - const string updatedRemoteName = "second-origin"; - const string updatedRemoteUrl = "git@github.com:mono/monohotdraw.git"; - EditRemote (updatedRemoteName, updatedRemoteUrl, "git@github.com:mono/monohotdraw-push.git"); - SelectRemote (updatedRemoteName, updatedRemoteUrl); - CloseRepositoryConfiguration (); - } - - [Test] - public void FetchRemoteBranches () - { - TestClone ("git@github.com:mono/jurassic.git"); - Ide.WaitForSolutionCheckedOut (); - - const string newRemoteName = "second"; - const string newRemoteUrl = "git@github.com:mono/monohotdraw.git"; - OpenRepositoryConfiguration ("Remote Sources"); - AddRemote (newRemoteName, newRemoteUrl); - FetchRemoteBranch (newRemoteName); - CloseRepositoryConfiguration (); - } - - [Test] - public void TrackRemoteBranchInLocalTest() - { - TestClone ("git@github.com:mono/jurassic.git"); - Ide.WaitForSolutionCheckedOut (); - - const string newRemoteName = "second"; - const string newRemoteUrl = "git@github.com:mono/monohotdraw.git"; - OpenRepositoryConfiguration ("Remote Sources"); - AddRemote (newRemoteName, newRemoteUrl); - FetchRemoteBranch (newRemoteName); - const string localBranch = "local-branch-random-uitest"; - CreateEditBranch ("buttonTrackRemote", localBranch); - SwitchTab ("Branches"); - SelectBranch (localBranch); - CloseRepositoryConfiguration (); - } - - #endregion - } - - public abstract class GitRepositoryConfigurationBase : VCSBase - { - #region Remotes - - Func<AppQuery, AppQuery> remoteTreeName = c => c.TreeView ().Marked ("treeRemotes").Model ("storeRemotes__Name"); - Func<AppQuery, AppQuery> remoteTreeUrl = c => c.TreeView ().Marked ("treeRemotes").Model ("storeRemotes__Url"); - Func<AppQuery, AppQuery> remoteTreeFullName = c => c.TreeView ().Marked ("treeRemotes").Model ("storeRemotes__FullName"); - - protected void SelectRemote (string remoteName, string remoteUrl = null) - { - Session.WaitForElement (c => remoteTreeName (c).Contains (remoteName)); - Assert.IsTrue (Session.SelectElement (c => remoteTreeName (c).Contains (remoteName))); - if (remoteUrl != null) { - Assert.IsTrue (Session.SelectElement (c => remoteTreeUrl (c).Contains (remoteUrl))); - } - TakeScreenShot (string.Format ("{0}-Remote-Selected", remoteName)); - } - - protected void EditRemote (string newRemoteName, string remoteUrl, string remotePushUrl = null) - { - AddEditRemote ("buttonEditRemote", newRemoteName, remoteUrl, remotePushUrl); - } - - protected void AddRemote (string newRemoteName, string remoteUrl, string remotePushUrl = null) - { - AddEditRemote ("buttonAddRemote", newRemoteName, remoteUrl, remotePushUrl); - } - - protected void FetchRemoteBranch (string remoteName) - { - SelectRemote (remoteName); - - Assert.IsEmpty (Session.Query (c => remoteTreeFullName (c).Contains (remoteName+"/"))); - Assert.IsTrue (Session.ClickElement (c => IdeQuery.GitConfigurationDialog (c).Children ().Button ().Marked ("buttonFetch"))); - TakeScreenShot ("Fetch-Remote"); - - Session.ClickElement (c => remoteTreeName (c).Contains (remoteName)); - Assert.IsNotEmpty (Session.Query (c => remoteTreeFullName (c).Contains (remoteName+"/"))); - Assert.IsTrue (Session.SelectElement (c => remoteTreeFullName (c).Contains (remoteName+"/").Index (0))); - TakeScreenShot ("First-Remote-Branch-Selected"); - } - - void AddEditRemote (string buttonName, string newRemoteName, string remoteUrl, string remotePushUrl) - { - Assert.IsNotEmpty (Session.Query (c => IdeQuery.GitConfigurationDialog (c).Children ().Button ().Marked (buttonName))); - Session.ClickElement (c => IdeQuery.GitConfigurationDialog (c).Children ().Button ().Marked (buttonName), false); - Session.WaitForElement (IdeQuery.EditRemoteDialog); - - Func<AppQuery, AppQuery> EditRemoteDialogChildren = c => IdeQuery.EditRemoteDialog (c).Children (); - Assert.IsTrue (Session.EnterText (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryName"), newRemoteName)); - Session.WaitForElement (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryName").Text (newRemoteName)); - - Assert.IsTrue (Session.EnterText (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryUrl"), remoteUrl)); - Session.WaitForElement (c => EditRemoteDialogChildren (c).Marked ("entryUrl").Text (remoteUrl)); - - Assert.IsTrue (Session.EnterText (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryPushUrl"), remotePushUrl ?? remoteUrl)); - Session.WaitForElement (c => EditRemoteDialogChildren (c).Textfield ().Marked ("entryPushUrl").Text (remotePushUrl ?? remoteUrl)); - TakeScreenShot ("Remote-Details-Filled"); - - Assert.IsTrue (Session.ClickElement (c => EditRemoteDialogChildren (c).Button ().Marked ("buttonOk"))); - Session.WaitForNoElement (IdeQuery.EditRemoteDialog); - Session.WaitForElement (IdeQuery.GitConfigurationDialog); - TakeScreenShot ("Remote-Edit-Dialog-Closed"); - } - - #endregion - - #region Branches - - Func<AppQuery, AppQuery> branchDisplayName = c => c.TreeView ().Marked ("listBranches").Model ("storeBranches__DisplayName"); - - protected void CreateNewBranch (string newBranchName) - { - CreateEditBranch ("buttonAddBranch", newBranchName); - } - - protected void EditBranch (string oldBranchName, string newBranchName) - { - SelectBranch (oldBranchName); - CreateEditBranch ("buttonEditBranch", newBranchName); - } - - protected void CreateEditBranch (string buttonName, string newBranchName) - { - Session.ClickElement (c => IdeQuery.GitConfigurationDialog(c).Children ().Button ().Marked (buttonName), false); - Session.WaitForElement (IdeQuery.EditBranchDialog); - TakeScreenShot ("Edit-Branch-Dialog-Opened"); - - Session.EnterText (c => IdeQuery.EditBranchDialog (c).Children ().Textfield ().Marked ("entryName"), newBranchName); - Session.WaitForElement (c => IdeQuery.EditBranchDialog (c).Children ().Textfield ().Marked ("entryName").Text (newBranchName)); - TakeScreenShot ("Branch-Name-Entered"); - - Assert.IsTrue (Session.ClickElement (c => IdeQuery.EditBranchDialog (c).Children ().Button ().Marked ("buttonOk"))); - Session.WaitForElement (IdeQuery.GitConfigurationDialog); - TakeScreenShot ("Edit-Branch-Dialog-Opened-Closed"); - } - - protected void SwitchToBranch (string branchName) - { - SelectBranch (branchName); - TakeScreenShot (string.Format ("{0}-Branch-Selected", branchName)); - Session.ClickElement (c => IdeQuery.GitConfigurationDialog(c).Children ().Button ().Marked ("buttonSetDefaultBranch"), false); - - try { - Session.WaitForElement (IdeQuery.GitConfigurationDialog); - TakeScreenShot ("Git-User-Not-Configured"); - EnterGitUserConfig ("John Doe", "john.doe@example.com"); - } catch (TimeoutException e) { } - - Assert.IsTrue (IsBranchSwitched (branchName)); - TakeScreenShot (string.Format ("Switched-To-{0}", branchName)); - } - - protected void SwitchTab (string tabName) - { - Assert.IsTrue (Session.SelectElement (c => IdeQuery.GitConfigurationDialog(c).Children ().Notebook ().Marked ("notebook1").Text (tabName))); - TakeScreenShot (string.Format ("Tab-Changed-{0}", GenerateProjectName (tabName))); - } - - protected void SelectBranch (string branchName) - { - Assert.IsTrue (Session.SelectElement (c => branchDisplayName (c).Contains (branchName))); - TakeScreenShot (string.Format ("Selected-Branch-{0}", branchName)); - } - - protected bool IsBranchSwitched (string branchName) - { - return Session.SelectElement (c => branchDisplayName (c).Text ("<b>" + branchName + "</b>")); - } - - #endregion - - protected void OpenRepositoryConfiguration (string selectTab = null) - { - Session.ExecuteCommand (MonoDevelop.VersionControl.Git.Commands.ManageBranches); - Session.WaitForElement (IdeQuery.GitConfigurationDialog); - TakeScreenShot ("Repository-Configuration-Opened"); - if (selectTab != null) - SwitchTab (selectTab); - } - - protected void CloseRepositoryConfiguration () - { - Session.ClickElement (c => IdeQuery.GitConfigurationDialog(c).Children ().Button ().Marked ("buttonOk")); - Session.WaitForNoElement (IdeQuery.GitConfigurationDialog); - } - } -} - diff --git a/main/tests/UserInterfaceTests/VersionControlTests/VCSBase.cs b/main/tests/UserInterfaceTests/VersionControlTests/VCSBase.cs index cf599626fd..e439d46580 100644 --- a/main/tests/UserInterfaceTests/VersionControlTests/VCSBase.cs +++ b/main/tests/UserInterfaceTests/VersionControlTests/VCSBase.cs @@ -26,7 +26,7 @@ using System; using NUnit.Framework; -using MonoDevelop.Components.AutoTest; +using MonoDevelop.Ide.Commands; namespace UserInterfaceTests { @@ -41,18 +41,34 @@ namespace UserInterfaceTests protected string CheckoutOrClone (string repoUrl, string cloneToLocation = null, VersionControlType cvsType = VersionControlType.Git, int cloneTimeoutSecs = 180) { cloneToLocation = cloneToLocation ?? Util.CreateTmpDir ("clone"); + ReproStep ("Click on Version Control > Checkout from Menu Bar"); Session.ExecuteCommand (MonoDevelop.VersionControl.Commands.Checkout); - Session.WaitForElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Dialogs.SelectRepositoryDialog")); + + WaitForElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Dialogs.SelectRepositoryDialog"), + "Select Repository window should open", + "Select Reprository window did not open"); TakeScreenShot ("Checkout-Window-Ready"); + + ReproStep (string.Format ("Select Type to '{0}'", cvsType)); Assert.IsTrue (Session.SelectElement (c => c.Marked ("repCombo").Model ().Text (cvsType.ToString ()))); + + ReproStep (string.Format ("Enter URL as '{0}'", repoUrl)); Assert.IsTrue (Session.EnterText (c => c.Textfield ().Marked ("repositoryUrlEntry"), repoUrl)); + Assert.IsTrue (Session.EnterText (c => c.Textfield ().Marked ("entryFolder"), cloneToLocation)); Session.WaitForElement (c => c.Textfield ().Marked ("entryFolder").Text (cloneToLocation)); + TakeScreenShot ("Before-Clicking-OK"); + ReproStep ("Click OK"); Assert.IsTrue (Session.ClickElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Dialogs.SelectRepositoryDialog").Children ().Button ().Marked ("buttonOk"))); + Session.WaitForElement (c => c.Window ().Marked ("MonoDevelop.Ide.Gui.Dialogs.ProgressDialog"), 15000); TakeScreenShot ("CheckoutClone-In-Progress"); - Session.WaitForNoElement (c => c.Window ().Marked ("MonoDevelop.Ide.Gui.Dialogs.ProgressDialog"), cloneTimeoutSecs * 1000); + ReproStep ("Wait for Clone to Finish"); + WaitForElement (c => c.Window ().Marked ("MonoDevelop.Ide.Gui.Dialogs.ProgressDialog"), + string.Format ("Clone should finish within {0} seconds", cloneTimeoutSecs), + string.Format ("Clone failed to finish within {0} seconds", cloneTimeoutSecs), + cloneTimeoutSecs * 1000); return cloneToLocation; } @@ -65,38 +81,103 @@ namespace UserInterfaceTests protected void TestGitStash (string stashMsg, int timeoutStashSecs = 10) { + ReproStep ("Click on Version Control > Stash"); Session.ExecuteCommand (MonoDevelop.VersionControl.Git.Commands.Stash); - Session.WaitForElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Git.NewStashDialog")); + + WaitForElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Git.NewStashDialog"), "Stash Dialog should open", "Stash Dialog did not open"); TakeScreenShot ("Stash-Dialog-Opened"); + + ReproStep ("Enter a stash message"); Session.EnterText (c => c.Window ().Marked ("MonoDevelop.VersionControl.Git.NewStashDialog").Children ().Textfield ().Marked ("entryComment"), stashMsg); Session.WaitForElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Git.NewStashDialog").Children ().Textfield ().Marked ("entryComment").Text (stashMsg)); TakeScreenShot ("Stash-Message-Entered"); + + ReproStep ("Click on OK"); Session.ClickElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Git.NewStashDialog").Children ().Button ().Marked ("buttonOk")); Ide.WaitForStatusMessage (new [] { "Changes successfully stashed" }, timeoutStashSecs); } protected void TestGitUnstash () { + ReproStep ("Click on Version Control > Pop Stash"); Session.ExecuteCommand (MonoDevelop.VersionControl.Git.Commands.StashPop); - Ide.WaitForStatusMessage (new[] {"Stash successfully applied"}, 10); + + WaitForElement (() => Ide.WaitForStatusMessage (new[] {"Stash successfully applied"}, 10), "Stash should apply successfully", "Stash failed to apply"); } protected void TestCommit (string commitMsg) { + ReproStep ("Click on Version Control > Review Solution and Commit from Menu Bar"); Session.ExecuteCommand (MonoDevelop.VersionControl.Commands.SolutionStatus); + + ReproStep ("Wait for diff to be available"); + WaitForElement (c => c.Button ().Marked ("buttonCommit").Sensitivity (true), "Commit button should become enabled", "Commit button was not enabled"); + + ReproStep ("Click on Commit Button"); Session.ClickElement (c => c.Button ().Marked ("buttonCommit"), false); - Session.WaitForElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Dialogs.CommitDialog")); + + WaitForElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Dialogs.CommitDialog"), "Commit Dialog should open", "Commit Dialog did not open"); TakeScreenShot ("Commit-Dialog-Opened"); + + ReproStep ("Enter commit message and click on Commit"); Session.EnterText (c => c.Window ().Marked ("MonoDevelop.VersionControl.Dialogs.CommitDialog").Children ().TextView ().Marked ("textview"), commitMsg); TakeScreenShot ("Commit-Msg-Entered"); Session.ClickElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Dialogs.CommitDialog").Children ().Button ().Marked ("buttonCommit"), false); + CheckIfNameEmailNeeded (); + CheckIfUserConflict (); + + WaitForElement (() => Ide.WaitForStatusMessage (new [] { "Commit operation completed." }), + "Status bar should show 'Commit operation completed.'", + "Status bar did not show 'Commit operation completed.'"); + TakeScreenShot ("Commit-Completed"); + + ReproStep ("Close currently commit tab"); + Session.ExecuteCommand (FileCommands.CloseFile); + Session.WaitForElement (IdeQuery.TextArea); + } + + protected void GitCreateAndCommit (TemplateSelectionOptions templateOptions, string commitMessage) + { + CreateProject (templateOptions, + new ProjectDetails (templateOptions), + new GitOptions { UseGit = true, UseGitIgnore = true }); + + Session.WaitForElement (IdeQuery.TextArea); + TestCommit (commitMessage); + } + + protected string MakeSomeChangesAndSaveAll (string waitForFile = null) + { + if (waitForFile != null) { + WaitForElement (c => c.Window ().Marked ("MonoDevelop.Ide.Gui.DefaultWorkbench").Property ("TabControl.CurrentTab.Text", waitForFile), + string.Format ("File '{0}' should open", waitForFile), + string.Format ("File {0} did not open", waitForFile)); + } + + Session.WaitForElement (IdeQuery.TextArea); + TakeScreenShot ("Ready-To-Make-Changes"); + Session.SelectElement (IdeQuery.TextArea); + ReproStep ("Make some random changes to the file"); + for (int i = 0; i < 10; i++) { + Session.ExecuteCommand (TextEditorCommands.InsertNewLine); + Session.ExecuteCommand (TextEditorCommands.InsertTab); + } + TakeScreenShot ("Made-Changes-To-Doc"); + + ReproStep ("Click on File > Save All from Menu Bar"); + Session.ExecuteCommand (FileCommands.SaveAll); + TakeScreenShot ("Inserted-Newline-SaveAll-Called"); + + return "Entered new blank line"; + } + + protected void CheckIfNameEmailNeeded () + { try { Session.WaitForElement (c => c.Window ().Marked ("MonoDevelop.VersionControl.Git.UserGitConfigDialog")); TakeScreenShot ("Git-User-Not-Configured"); EnterGitUserConfig ("John Doe", "john.doe@example.com"); } catch (TimeoutException e) { } - Ide.WaitForStatusMessage (new[] {"Commit operation completed."}); - TakeScreenShot ("Commit-Completed"); } protected void EnterGitUserConfig (string gitUser, string gitEmail) @@ -119,6 +200,15 @@ namespace UserInterfaceTests } } + protected void CheckIfUserConflict () + { + try { + Session.WaitForElement (c => c.Window ().Marked ("User Information Conflict")); + Session.ClickElement (c => c.Window ().Marked ("User Information Conflict").Children ().Button ().Text ("OK")); + } catch (TimeoutException) { + } + } + protected override void OnBuildTemplate (int buildTimeoutInSecs = 180) { } diff --git a/main/tests/UserInterfaceTests/Workbench.cs b/main/tests/UserInterfaceTests/Workbench.cs new file mode 100644 index 0000000000..9ddb3bdf1a --- /dev/null +++ b/main/tests/UserInterfaceTests/Workbench.cs @@ -0,0 +1,147 @@ +// +// Workbench.cs +// +// Author: +// Manish Sinha <manish.sinha@xamarin.com> +// +// Copyright (c) 2015 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using MonoDevelop.Core; +using MonoDevelop.Components.AutoTest; +using System.Text.RegularExpressions; +using MonoDevelop.Ide.Commands; +using System.Linq; + +namespace UserInterfaceTests +{ + public static class Workbench + { + static AutoTestClientSession Session { + get { return TestService.Session; } + } + + static readonly Regex buildRegex = new Regex (@"Build: (?<errors>\d*) error\D*, (?<warnings>\d*) warning\D*", RegexOptions.Compiled); + + public static string GetStatusMessage (int timeout = 20000, bool waitForNonEmpty = true) + { + if (Platform.IsMac) { + if (waitForNonEmpty) { + Ide.WaitUntil ( + () => Session.GetGlobalValue<string> ("MonoDevelop.Ide.IdeApp.Workbench.RootWindow.StatusBar.text") != string.Empty, + timeout + ); + } + return (string)Session.GetGlobalValue ("MonoDevelop.Ide.IdeApp.Workbench.RootWindow.StatusBar.text"); + } + + if (waitForNonEmpty) { + Ide.WaitUntil ( + () => Session.GetGlobalValue<int> ("MonoDevelop.Ide.IdeApp.Workbench.RootWindow.StatusBar.messageQueue.Count") == 0, + timeout, + timeoutMessage: ()=> "MessageQueue.Count="+Session.GetGlobalValue<int> ("MonoDevelop.Ide.IdeApp.Workbench.RootWindow.StatusBar.messageQueue.Count") + ); + } + return (string) Session.GetGlobalValue ("MonoDevelop.Ide.IdeApp.Workbench.RootWindow.StatusBar.renderArg.CurrentText"); + } + + public static bool IsBuildSuccessful (int timeoutInSecs) + { + bool isBuildSuccessful = false; + Ide.WaitUntil (() => { + var actualStatusMessage = Workbench.GetStatusMessage (); + if (actualStatusMessage == "Build successful.") { + isBuildSuccessful = true; + return true; + } + if (actualStatusMessage == "Build failed.") { + isBuildSuccessful = false; + return true; + } + var match = buildRegex.Match (actualStatusMessage); + if (match != null && match.Success) { + isBuildSuccessful = string.Equals (match.Groups ["errors"].ToString (), "0"); + return true; + } + return false; + }, + pollStep: 5 * 1000, + timeout: timeoutInSecs * 1000, + timeoutMessage: () => "GetStatusMessage=" + Workbench.GetStatusMessage ()); + + return isBuildSuccessful; + } + + public static bool Run (int timeoutSeconds = 20, int pollStepSecs = 5) + { + Session.ExecuteCommand (ProjectCommands.Run); + try { + Ide.WaitUntil ( + () => !Session.Query (c => IdeQuery.RunButton (c).Property ("Icon", "Stop")).Any (), + timeout: timeoutSeconds * 1000, pollStep: pollStepSecs * 1000); + return false; + } catch (TimeoutException) { + return true; + } + } + + public static void OpenWorkspace (string solutionPath, UITestBase testContext = null) + { + if (testContext != null) + testContext.ReproStep (string.Format ("Open solution path '{0}'", solutionPath)); + Action<string> takeScreenshot = GetScreenshotAction (testContext); + Session.GlobalInvoke ("MonoDevelop.Ide.IdeApp.Workspace.OpenWorkspaceItem", new FilePath (solutionPath), true); + Ide.WaitForIdeIdle (); + takeScreenshot ("Solution-Opened"); + } + + public static void CloseWorkspace (UITestBase testContext = null) + { + if (testContext != null) + testContext.ReproStep ("Close current workspace"); + Action<string> takeScreenshot = GetScreenshotAction (testContext); + takeScreenshot ("About-To-Close-Workspace"); + Session.ExecuteCommand (FileCommands.CloseWorkspace); + takeScreenshot ("Closed-Workspace"); + } + + public static string Configuration + { + get { + var configId = Session.GetGlobalValue ("MonoDevelop.Ide.IdeApp.Workspace.ActiveConfigurationId"); + return configId != null ? (string)configId : null; + } + set { + Session.SetGlobalValue ("MonoDevelop.Ide.IdeApp.Workspace.ActiveConfigurationId", value); + Ide.WaitUntil (() => Workbench.Configuration == value, timeoutMessage: () => "Failed to set Configuration, Configuration=" + Workbench.Configuration + " value=" + value); + } + } + + public static Action<string> GetScreenshotAction (UITestBase testContext) + { + Action<string> takeScreenshot = delegate { + }; + if (testContext != null) + takeScreenshot = testContext.TakeScreenShot; + + return takeScreenshot; + } + } +} |