public void TestLongPathCheck() { string[] expectedLongPaths = { @"node_modules\azure\node_modules\azure-common\node_modules\xml2js\node_modules\sax\test\trailing-attribute-no-value.js", @"node_modules\azure\node_modules\azure-common\node_modules\xml2js\node_modules\sax\test\xmlns-xml-default-prefix-attribute.js", @"node_modules\azure\node_modules\azure-common\node_modules\xml2js\node_modules\sax\test\xmlns-xml-default-redefine.js", @"node_modules\azure\node_modules\request\node_modules\form-data\node_modules\combined-stream\node_modules", @"node_modules\azure\node_modules\request\node_modules\http-signature\node_modules\ctype\tst\ctio\uint\tst.roundtrip.js", }; string projectDir = CreateTempPathOfLength(248 - 1 - expectedLongPaths.Min(s => s.Length)); try { foreach (var fileName in new[] { "HelloWorld.njsproj", "HelloWorld.sln", "package.json", "README.md", "server.js" }) { File.Copy(TestData.GetPath(@"TestData\HelloWorld\" + fileName), projectDir + "\\" + fileName); } using (var app = new NodejsVisualStudioApp()) { try { NodejsPackage.Instance.GeneralOptionsPage.CheckForLongPaths = true; var project = app.OpenProject(projectDir + "\\HelloWorld.sln"); // Wait for new solution to load. for (int i = 0; i < 40 && app.Dte.Solution.Projects.Count == 0; i++) { System.Threading.Thread.Sleep(250); } const string interpreterDescription = "Node.js Interactive Window"; app.Dte.ExecuteCommand("View.Node.jsInteractiveWindow"); var interactive = app.GetInteractiveWindow(interpreterDescription); if (interactive == null) { Assert.Inconclusive("Need " + interpreterDescription); } interactive.WaitForIdleState(); var npmTask = interactive.ReplWindow.ExecuteCommand(".npm install [email protected]"); using (var dialog = new AutomationDialog(app, AutomationElement.FromHandle(app.WaitForDialog(npmTask)))) { // The option to offer "npm dedupe" should be there. var firstCommandLink = dialog.FindByAutomationId("CommandLink_1000"); Assert.IsNotNull(firstCommandLink); Assert.IsTrue(firstCommandLink.Current.Name.Contains("npm dedupe")); dialog.ClickButtonByAutomationId("ExpandoButton"); var detailsText = dialog.FindByAutomationId("ExpandedFooterTextLink"); Assert.IsNotNull(detailsText); var reportedLongPaths = (from line in detailsText.Current.Name.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) where line.StartsWith("•") let nbspIndex = line.IndexOf('\u00A0') where nbspIndex >= 0 select line.Substring(1, nbspIndex - 1).Trim() ).ToArray(); Console.WriteLine("Reported paths:"); foreach (var path in reportedLongPaths) { Console.WriteLine("\t" + path); } reportedLongPaths = reportedLongPaths.Except(expectedLongPaths).ToArray(); if (reportedLongPaths.Length != 0) { Console.WriteLine("Unexpected paths:"); foreach (var path in reportedLongPaths) { Console.WriteLine("\t" + path); } Assert.Fail("Unexpected long paths reported."); } dialog.WaitForClosed(TimeSpan.FromSeconds(1), () => { // Click the first command button (dedupe). firstCommandLink.SetFocus(); Keyboard.Press(System.Windows.Input.Key.Enter); }); } // Clicking on that button should not change the option. Assert.IsTrue(NodejsPackage.Instance.GeneralOptionsPage.CheckForLongPaths); interactive.WaitForTextContainsAll("dedupe successfully completed"); interactive.WaitForIdleState(); // npm dedupe won't be able to fix the problem, so we should get the dialog once again. using (var dialog = new AutomationDialog(app, AutomationElement.FromHandle(app.WaitForDialog(npmTask)))) { // The option to offer "npm dedupe" should not be there anymore. var firstCommandLink = dialog.FindByAutomationId("CommandLink_1000"); Assert.IsNotNull(firstCommandLink); Assert.IsFalse(firstCommandLink.Current.Name.Contains("npm dedupe")); dialog.WaitForClosed(TimeSpan.FromSeconds(1), () => { Keyboard.Type("\r"); // click the first command button (do nothing, but warn next time) }); } npmTask.Wait(1000); Assert.IsTrue(npmTask.IsCompleted); // Clicking on that button should not change the option. Assert.IsTrue(NodejsPackage.Instance.GeneralOptionsPage.CheckForLongPaths); // Try again to see that the dialog still appears. Any npm command triggers the check. // and since we didn't do anything to fix the problem, we should still get the dialog. interactive.WaitForIdleState(); npmTask = interactive.ReplWindow.ExecuteCommand(".npm list"); using (var dialog = new AutomationDialog(app, AutomationElement.FromHandle(app.WaitForDialog(npmTask)))) { // The option to offer "npm dedupe" should be there again, since this is a new check. var firstCommandLink = dialog.FindByAutomationId("CommandLink_1000"); Assert.IsNotNull(firstCommandLink); Assert.IsTrue(firstCommandLink.Current.Name.Contains("npm dedupe")); dialog.WaitForClosed(TimeSpan.FromSeconds(1), () => { // Click the third command button (do nothing, do not warn anymore) firstCommandLink.SetFocus(); Keyboard.Press(System.Windows.Input.Key.Tab); Keyboard.Press(System.Windows.Input.Key.Tab); Keyboard.Press(System.Windows.Input.Key.Enter); }); } npmTask.Wait(1000); Assert.IsTrue(npmTask.IsCompleted); // Clicking on that button should change the option to false. Assert.IsFalse(NodejsPackage.Instance.GeneralOptionsPage.CheckForLongPaths); // Try again to see that the dialog does not appear anymore. interactive.WaitForIdleState(); npmTask = interactive.ReplWindow.ExecuteCommand(".npm list"); app.WaitForNoDialog(TimeSpan.FromSeconds(3)); } finally { NodejsPackage.Instance.GeneralOptionsPage.CheckForLongPaths = true; } } } finally { DeleteLongPath(projectDir); } }
public void CustomCommandsRequiredPackages() { using (var app = new PythonVisualStudioApp()) using (var dis = app.SelectDefaultInterpreter(PythonVersion, "virtualenv")) { PythonProjectNode node; EnvDTE.Project proj; OpenProject(app, "CommandRequirePackages.sln", out node, out proj); string envName; var env = app.CreateVirtualEnvironment(proj, out envName); env.Select(); app.Dte.ExecuteCommand("Python.ActivateEnvironment"); // Ensure that no error dialog appears app.WaitForNoDialog(TimeSpan.FromSeconds(5.0)); // First, execute the command and cancel it. var task = ExecuteAsync(node, "Require Packages"); try { var dialogHandle = app.WaitForDialog(task); if (dialogHandle == IntPtr.Zero) { if (task.IsFaulted && task.Exception != null) { Assert.Fail("Unexpected exception in package install confirmation dialog:\n{0}", task.Exception); } else { Assert.AreNotEqual(IntPtr.Zero, dialogHandle); } } using (var dialog = new AutomationDialog(app, AutomationElement.FromHandle(dialogHandle))) { var label = dialog.FindByAutomationId("CommandLink_1000"); Assert.IsNotNull(label); string expectedLabel = "The following packages will be installed using pip:\r\n" + "\r\n" + "ptvsd\r\n" + "azure==0.1";; Assert.AreEqual(expectedLabel, label.Current.HelpText); dialog.Cancel(); try { task.Wait(1000); Assert.Fail("Command was not canceled after dismissing the package install confirmation dialog"); } catch (AggregateException ex) { if (!(ex.InnerException is TaskCanceledException)) { throw; } } } } finally { if (!task.IsCanceled && !task.IsCompleted && !task.IsFaulted) { if (task.Wait(10000)) { task.Dispose(); } } else { task.Dispose(); } } // Then, execute command and allow it to proceed. task = ExecuteAsync(node, "Require Packages"); try { var dialogHandle = app.WaitForDialog(task); if (dialogHandle == IntPtr.Zero) { if (task.IsFaulted && task.Exception != null) { Assert.Fail("Unexpected exception in package install confirmation dialog:\n{0}", task.Exception); } else { Assert.AreNotEqual(IntPtr.Zero, dialogHandle); } } using (var dialog = new AutomationDialog(app, AutomationElement.FromHandle(dialogHandle))) { dialog.ClickButtonAndClose("CommandLink_1000", nameIsAutomationId: true); } task.Wait(); var ver = PythonVersion.Version.ToVersion(); ExpectOutputWindowText(app, string.Format("pass {0}.{1}", ver.Major, ver.Minor)); } finally { if (!task.IsCanceled && !task.IsCompleted && !task.IsFaulted) { if (task.Wait(10000)) { task.Dispose(); } } else { task.Dispose(); } } } }