internal override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { if (cmdGroup == Guids.NodejsCmdSet) { switch (cmd) { case PkgCmdId.cmdidOpenReplWindow: NodejsPackage.Instance.OpenReplWindow(); return(VSConstants.S_OK); } } else if (cmdGroup == Guids.NodejsNpmCmdSet) { try { NpmHelpers.GetPathToNpm( Nodejs.GetAbsoluteNodeExePath( this.ProjectHome, this.Project.GetNodejsProject().GetProjectProperty(NodeProjectProperty.NodeExePath) )); } catch (NpmNotFoundException) { Nodejs.ShowNodejsNotInstalled(); return(VSConstants.S_OK); } } return(base.ExecCommandOnNode(cmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut)); }
protected override int ExecCommandThatDependsOnSelectedNodes(Guid cmdGroup, uint cmdId, uint cmdExecOpt, IntPtr vaIn, IntPtr vaOut, CommandOrigin commandOrigin, IList <HierarchyNode> selectedNodes, out bool handled) { if (cmdGroup == Guids.NodejsNpmCmdSet) { try { NpmHelpers.GetPathToNpm(this.Project.GetNodejsProject().GetProjectProperty(NodejsConstants.NodeExePath)); } catch (NpmNotFoundException) { Nodejs.ShowNodejsNotInstalled(); handled = true; return(VSConstants.S_OK); } switch (cmdId) { case PkgCmdId.cmdidNpmManageModules: if (!ShowManageModulesCommandOnNode(selectedNodes)) { ModulesNode.ManageModules(); handled = true; return(VSConstants.S_OK); } var node = selectedNodes[0] as AbstractNpmNode; if (node != null) { var abstractNpmNode = node; abstractNpmNode.ManageNpmModules(); handled = true; return(VSConstants.S_OK); } break; } } return(base.ExecCommandThatDependsOnSelectedNodes(cmdGroup, cmdId, cmdExecOpt, vaIn, vaOut, commandOrigin, selectedNodes, out handled)); }
public static string GetPathToNpm(string nodePath = null) { var path = GetNpmPathFromNodePath(nodePath); if (!string.IsNullOrEmpty(path)) { return(path); } string executable = "npm.cmd"; path = Nodejs.GetPathToNodeExecutableFromEnvironment(executable); if (string.IsNullOrEmpty(path)) { throw new NpmNotFoundException( string.Format(CultureInfo.CurrentCulture, "Cannot find {0} in the registry, your path, or under " + "program files in the nodejs folder. Ensure Node.js is installed.", executable ) ); } return(path); }
private int Start(string file, bool debug) { var nodePath = GetNodePath(); if (nodePath == null) { Nodejs.ShowNodejsNotInstalled(); return(VSConstants.S_OK); } bool startBrowser = ShouldStartBrowser(); #if !DEV15 bool useWebKitDebugger = false; #else bool useWebKitDebugger = NodejsPackage.Instance.GeneralOptionsPage.UseWebKitDebugger; #endif if (debug && !useWebKitDebugger) { StartWithDebugger(file); } else if (debug && useWebKitDebugger) { StartAndAttachDebugger(file, nodePath); } else { StartNodeProcess(file, nodePath, startBrowser); } return(VSConstants.S_OK); }
public int LaunchFile(string file, bool debug) { var nodePath = GetNodePath(); if (nodePath == null) { Nodejs.ShowNodejsNotInstalled(); return(VSConstants.S_OK); } var nodeVersion = Nodejs.GetNodeVersion(nodePath); var startBrowser = ShouldStartBrowser(); // The call to Version.ToString() is safe, since changes to the ToString method are very unlikely, as the current output is widely documented. if (debug) { if (nodeVersion >= new Version(8, 0)) { StartWithChromeV2Debugger(file, nodePath, startBrowser); TelemetryHelper.LogDebuggingStarted("ChromeV2", nodeVersion.ToString()); } else { StartWithDebugger(file); TelemetryHelper.LogDebuggingStarted("Node6", nodeVersion.ToString()); } } else { StartNodeProcess(file, nodePath, startBrowser); TelemetryHelper.LogDebuggingStarted("None", nodeVersion.ToString()); } return(VSConstants.S_OK); }
protected override int ExecCommandThatDependsOnSelectedNodes(Guid cmdGroup, uint cmdId, uint cmdExecOpt, IntPtr vaIn, IntPtr vaOut, CommandOrigin commandOrigin, IList <HierarchyNode> selectedNodes, out bool handled) { if (cmdGroup == Guids.NodejsNpmCmdSet) { try { NpmHelpers.GetPathToNpm( Nodejs.GetAbsoluteNodeExePath( ProjectHome, Project.GetNodejsProject().GetProjectProperty(NodeProjectProperty.NodeExePath) )); } catch (NpmNotFoundException) { Nodejs.ShowNodejsNotInstalled(); handled = true; return(VSConstants.S_OK); } switch (cmdId) { case PkgCmdId.cmdidNpmManageModules: if (!ShowManageModulesCommandOnNode(selectedNodes)) { ModulesNode.ManageModules(); handled = true; return(VSConstants.S_OK); } var node = selectedNodes[0] as AbstractNpmNode; if (node != null) { var abstractNpmNode = node; abstractNpmNode.ManageNpmModules(); handled = true; return(VSConstants.S_OK); } break; } } else if (cmdGroup == Guids.NodejsCmdSet) { switch (cmdId) { case PkgCmdId.cmdidSetAsNodejsStartupFile: // Set the StartupFile project property to the Url of this node SetProjectProperty( CommonConstants.StartupFile, CommonUtils.GetRelativeFilePath(ProjectHome, selectedNodes[0].Url) ); handled = true; return(VSConstants.S_OK); case PkgCmdId.cmdidAddFileCommand: NewFileMenuGroup.NewFileUtilities.CreateNewFile(projectNode: this, containerId: selectedNodes[0].ID); handled = true; return(VSConstants.S_OK); } } return(base.ExecCommandThatDependsOnSelectedNodes(cmdGroup, cmdId, cmdExecOpt, vaIn, vaOut, commandOrigin, selectedNodes, out handled)); }
public void CheckAbsoluteNodeExePathResolution() { var path = @"C:\Program Files\node.exe"; var dir = Path.GetDirectoryName(path); Assert.AreEqual(path, Nodejs.GetAbsoluteNodeExePath(@"C:\myprojectpath", path), "Resolution should use absolute path if specified"); }
private int Start(string file, bool debug) { string nodePath = GetNodePath(); if (nodePath == null) { Nodejs.ShowNodejsNotInstalled(); return(VSConstants.S_OK); } bool startBrowser = ShouldStartBrowser(); if (debug) { StartWithDebugger(file); } else { var psi = new ProcessStartInfo(); psi.UseShellExecute = false; psi.FileName = nodePath; psi.Arguments = GetFullArguments(file); psi.WorkingDirectory = _project.GetWorkingDirectory(); string webBrowserUrl = GetFullUrl(); Uri uri = null; if (!String.IsNullOrWhiteSpace(webBrowserUrl)) { uri = new Uri(webBrowserUrl); psi.EnvironmentVariables["PORT"] = uri.Port.ToString(); } foreach (var nameValue in GetEnvironmentVariables()) { psi.EnvironmentVariables[nameValue.Key] = nameValue.Value; } var process = NodeProcess.Start( psi, NodejsPackage.Instance.GeneralOptionsPage.WaitOnAbnormalExit, NodejsPackage.Instance.GeneralOptionsPage.WaitOnNormalExit); _project.OnDispose += process.ResponseToTerminateEvent; if (startBrowser && uri != null) { OnPortOpenedHandler.CreateHandler( uri.Port, shortCircuitPredicate: () => process.HasExited, action: () => { VsShellUtilities.OpenBrowser(webBrowserUrl, (uint)__VSOSPFLAGS.OSP_LaunchNewBrowser); } ); } } return(VSConstants.S_OK); }
private void NodeExePathChanged(object sender, EventArgs e) { if (!string.IsNullOrEmpty(this._nodeExePath.Text) && !this._nodeExePath.Text.Contains("$(") && !File.Exists(Nodejs.GetAbsoluteNodeExePath(this._propPage.Project.ProjectHome, this._nodeExePath.Text))) { DisplayWarning(Resources.NodeExePathNotFound); } Changed(sender, e); }
private void NodeExePathChanged(object sender, EventArgs e) { if (string.IsNullOrEmpty(this._nodeExePath.Text) || this._nodeExePath.Text.Contains("$(") || File.Exists(Nodejs.GetAbsoluteNodeExePath(this._propPage.Project.ProjectHome, this._nodeExePath.Text))) { this._nodeExeErrorProvider.SetError(this._nodeExePath, string.Empty); } else { this._nodeExeErrorProvider.SetError(this._nodeExePath, Resources.NodeExePathNotFound); } Changed(sender, e); }
private void NodeExePathChanged(object sender, EventArgs e) { if (String.IsNullOrEmpty(_nodeExePath.Text) || _nodeExePath.Text.Contains("$(") || File.Exists(Nodejs.GetAbsoluteNodeExePath(_propPage.Project.ProjectHome, _nodeExePath.Text))) { _nodeExeErrorProvider.SetError(_nodeExePath, String.Empty); } else { _nodeExeErrorProvider.SetError(_nodeExePath, SR.GetString(SR.NodeExePathNotFound)); } Changed(sender, e); }
public void SetupDebugTargetInfo(ref VsDebugTargetInfo vsDebugTargetInfo, DebugLaunchActionContext debugLaunchContext) { var nodeExe = debugLaunchContext.LaunchConfiguration.GetValue(NodeExeKey, defaultValue: Nodejs.GetPathToNodeExecutableFromEnvironment()); var nodeVersion = Nodejs.GetNodeVersion(nodeExe); if (nodeVersion >= new Version(8, 0) || NodejsProjectLauncher.CheckDebugProtocolOption()) { SetupDebugTargetInfoForWebkitV2Protocol(ref vsDebugTargetInfo, debugLaunchContext, nodeExe); TelemetryHelper.LogDebuggingStarted("ChromeV2", nodeVersion.ToString(), isProject: false); } else { this.SetupDebugTargetInfoForNodeProtocol(ref vsDebugTargetInfo, debugLaunchContext, nodeExe); TelemetryHelper.LogDebuggingStarted("Node6", nodeVersion.ToString(), isProject: false); } }
void IVsDebugLaunchTargetProvider.SetupDebugTargetInfo(ref VsDebugTargetInfo vsDebugTargetInfo, DebugLaunchActionContext debugLaunchContext) { var nodeExe = CheckNodeInstalledAndWarn(debugLaunchContext); var nodeVersion = Nodejs.GetNodeVersion(nodeExe); if (nodeVersion >= new Version(8, 0)) { this.SetupDebugTargetInfoForInspectProtocol(ref vsDebugTargetInfo, debugLaunchContext, nodeExe); TelemetryHelper.LogDebuggingStarted("ChromeV2", nodeVersion.ToString(), isProject: false); } else { this.SetupDebugTargetInfoForNodeProtocol(ref vsDebugTargetInfo, debugLaunchContext, nodeExe); TelemetryHelper.LogDebuggingStarted("Node6", nodeVersion.ToString(), isProject: false); } }
private string GetNodeExePath() { var startupProject = this.site.GetStartupProject(); string nodeExePath; if (startupProject != null) { nodeExePath = Nodejs.GetAbsoluteNodeExePath( startupProject.ProjectHome, startupProject.GetProjectProperty(NodeProjectProperty.NodeExePath) ); } else { nodeExePath = Nodejs.NodeExePath; } return(nodeExePath); }
public void CheckRelativeNodeExePathResolution() { var path = @"C:\mynodepath\node.exe"; var dir = Path.GetDirectoryName(path); var filename = Path.GetFileName(path); Assert.AreEqual(path, Nodejs.GetAbsoluteNodeExePath(dir, filename), "Resolution failed when relative filename is surrounded by quotes"); Assert.AreEqual(path, Nodejs.GetAbsoluteNodeExePath(dir, "\"" + filename + "\""), "Resolution failed when relative filename is surrounded by quotes"); Assert.AreEqual(path, Nodejs.GetAbsoluteNodeExePath(dir, "./" + filename), "Resolution failed when relative filename begins with ./"); Assert.AreEqual(path, Nodejs.GetAbsoluteNodeExePath(dir, "../" + Path.GetFileName(dir) + "/" + filename), "Resolution failed when relative filename begins with ../"); Assert.AreEqual(".", Nodejs.GetAbsoluteNodeExePath(null, "."), "Resolution should return relative path on failure"); Assert.AreEqual(Nodejs.NodeExePath, Nodejs.GetAbsoluteNodeExePath(dir, null), "Resolution should fall back to environment path if no relative path is specified"); }
private int Start(string file, bool debug) { var nodePath = GetNodePath(); if (nodePath == null) { Nodejs.ShowNodejsNotInstalled(); return(VSConstants.S_OK); } var nodeVersion = Nodejs.GetNodeVersion(nodePath); var chromeProtocolRequired = nodeVersion >= new Version(8, 0) || CheckDebugProtocolOption(); var startBrowser = ShouldStartBrowser(); // The call to Version.ToString() is safe, since changes to the ToString method are very unlikely, as the current output is widely documented. if (debug && !chromeProtocolRequired) { StartWithDebugger(file); TelemetryHelper.LogDebuggingStarted("Node6", nodeVersion.ToString()); } else if (debug && chromeProtocolRequired) { if (CheckUseNewChromeDebugProtocolOption()) { StartWithChromeV2Debugger(file, nodePath, startBrowser); TelemetryHelper.LogDebuggingStarted("ChromeV2", nodeVersion.ToString()); } else { StartAndAttachDebugger(file, nodePath, startBrowser); TelemetryHelper.LogDebuggingStarted("Chrome", nodeVersion.ToString()); } } else { StartNodeProcess(file, nodePath, startBrowser); TelemetryHelper.LogDebuggingStarted("None", nodeVersion.ToString()); } return(VSConstants.S_OK); }
public override void Load(string filename, string location, string name, uint flags, ref Guid iidProject, out int canceled) { base.Load(filename, location, name, flags, ref iidProject, out canceled); // check the property var nodeProperty = GetProjectProperty(NodeProjectProperty.NodeExePath); if (!string.IsNullOrEmpty(nodeProperty)) { return; } // see if we can locate the Node.js runtime from the environment if (!string.IsNullOrEmpty(Nodejs.GetPathToNodeExecutableFromEnvironment())) { return; } // show info bar MissingNodeInfoBar.Show(this); }
internal void DiscoverTestFiles(string packageJsonPath, IMessageLogger logger, ITestCaseDiscoverySink discoverySink) { logger.SendMessage(TestMessageLevel.Informational, $"Parsing '{packageJsonPath}'."); var packageJson = PackageJsonFactory.Create(packageJsonPath); if (string.IsNullOrEmpty(packageJson.TestRoot)) { logger.SendMessage(TestMessageLevel.Informational, "No vsTestOptions|testRoot specified."); return; } var workingDir = Path.GetDirectoryName(packageJsonPath); var testFolderPath = Path.Combine(workingDir, packageJson.TestRoot); if (!Directory.Exists(testFolderPath)) { logger.SendMessage(TestMessageLevel.Error, $"Testroot '{packageJson.TestRoot}' doesn't exist."); return; } var testFx = default(TestFramework); foreach (var dep in packageJson.AllDependencies) { testFx = this.frameworkDiscoverer.GetFramework(dep.Name); if (testFx != null) { break; } } testFx = testFx ?? this.frameworkDiscoverer.GetFramework(TestFrameworkDirectories.ExportRunnerFrameworkName); var nodeExePath = Nodejs.GetPathToNodeExecutableFromEnvironment(); var worker = new TestDiscovererWorker(packageJsonPath, nodeExePath); worker.DiscoverTests(testFolderPath, testFx, logger, discoverySink, nameof(PackageJsonTestDiscoverer)); }
public async Task TestNpmReplCommandProcessExitSucceeds() { var npmPath = Nodejs.GetPathToNodeExecutableFromEnvironment("npm.cmd"); using (var eval = ProjectlessEvaluator()) { var mockWindow = new MockReplWindow(eval) { ShowAnsiCodes = true }; mockWindow.ClearScreen(); var redirector = new NpmReplCommand.NpmReplRedirector(mockWindow); for (int j = 0; j < 200; j++) { await NpmReplCommand.ExecuteNpmCommandAsync( redirector, npmPath, null, new[] { "config", "get", "registry" }, null); } } }
private int Start(string file, bool debug) { var nodePath = GetNodePath(); if (nodePath == null) { Nodejs.ShowNodejsNotInstalled(); return(VSConstants.S_OK); } var chromeProtocolRequired = Nodejs.GetNodeVersion(nodePath) >= new Version(8, 0); #if !DEV15 if (chromeProtocolRequired) { Nodejs.ShowNodeVersionNotSupported(); return(VSConstants.S_OK); } #endif bool startBrowser = ShouldStartBrowser(); if (debug && !chromeProtocolRequired) { StartWithDebugger(file); } else if (debug && chromeProtocolRequired) { StartAndAttachDebugger(file, nodePath); } else { StartNodeProcess(file, nodePath, startBrowser); } return(VSConstants.S_OK); }
public void SetupDebugTargetInfo(ref VsDebugTargetInfo vsDebugTargetInfo, DebugLaunchActionContext debugLaunchContext) { var nodeExe = debugLaunchContext.LaunchConfiguration.GetValue(NodeExeKey, defaultValue: Nodejs.GetPathToNodeExecutableFromEnvironment()); if (string.IsNullOrEmpty(nodeExe)) { var workspace = this.WorkspaceService.CurrentWorkspace; workspace.JTF.Run(async() => { await workspace.JTF.SwitchToMainThreadAsync(); VsShellUtilities.ShowMessageBox(this.ServiceProvider, string.Format(Resources.NodejsNotInstalledAnyCode, LaunchConfigurationConstants.LaunchJsonFileName), Resources.NodejsNotInstalledShort, OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); }); // This isn't pretty but the only way to not get an additional // dialog box, after the one we show. throw new TaskCanceledException(); } var nodeVersion = Nodejs.GetNodeVersion(nodeExe); if (nodeVersion >= new Version(8, 0) || NodejsProjectLauncher.CheckDebugProtocolOption()) { SetupDebugTargetInfoForWebkitV2Protocol(ref vsDebugTargetInfo, debugLaunchContext, nodeExe); TelemetryHelper.LogDebuggingStarted("ChromeV2", nodeVersion.ToString(), isProject: false); } else { this.SetupDebugTargetInfoForNodeProtocol(ref vsDebugTargetInfo, debugLaunchContext, nodeExe); TelemetryHelper.LogDebuggingStarted("Node6", nodeVersion.ToString(), isProject: false); } }
public void DiscoverTests(IEnumerable <string> sources, IDiscoveryContext discoveryContext, IMessageLogger logger, ITestCaseDiscoverySink discoverySink) { // we can ignore the sources argument since this will be a collection of assemblies. ValidateArg.NotNull(discoverySink, nameof(discoverySink)); ValidateArg.NotNull(logger, nameof(logger)); // extract the project file from the discovery context. var unitTestSettings = new UnitTestSettings(discoveryContext.RunSettings); if (string.IsNullOrEmpty(unitTestSettings.TestSource)) { // no need to log since the test executor will report 'no tests' return; } if (string.IsNullOrEmpty(unitTestSettings.TestFrameworksLocation)) { logger.SendMessage(TestMessageLevel.Error, "Failed to locate the test frameworks."); return; } sources = new[] { unitTestSettings.TestSource }; var frameworkDiscoverer = new FrameworkDiscoverer(unitTestSettings.TestFrameworksLocation); var projects = new List <(string projectFilePath, IEnumerable <XElement> propertyGroup)>(); // There's an issue when loading the project using the .NET Core msbuild bits, // so we load the xml, and extract the properties we care about. // Downside is we only have the raw contents of the XmlElements, i.e. we don't // expand any variables. // The issue we encountered is that the msbuild implementation was not able to // locate the SDK targets/props files. See: https://github.com/Microsoft/msbuild/issues/3434 try { foreach (var source in sources) { var cleanPath = source.Trim('\'', '"'); // we only support project files, e.g. csproj, vbproj, etc. if (!cleanPath.EndsWith("proj", StringComparison.OrdinalIgnoreCase)) { continue; } var project = XDocument.Load(cleanPath); // structure looks like Project/PropertyGroup/JsTestRoot and Project/PropertyGroup/JsTestFramework var propertyGroup = project.Descendants("Project").Descendants("PropertyGroup"); projects.Add((cleanPath, propertyGroup)); } foreach (var(projectFile, propertyGroup) in projects) { var testFramework = propertyGroup.Descendants(NodeProjectProperty.TestFramework).FirstOrDefault()?.Value; var testRoot = propertyGroup.Descendants(NodeProjectProperty.TestRoot).FirstOrDefault()?.Value; var outDir = propertyGroup.Descendants(NodeProjectProperty.TypeScriptOutDir).FirstOrDefault()?.Value ?? ""; if (string.IsNullOrEmpty(testRoot) || string.IsNullOrEmpty(testFramework)) { logger.SendMessage(TestMessageLevel.Warning, $"No TestRoot or TestFramework specified for '{Path.GetFileName(projectFile)}'."); continue; } var projectHome = Path.GetDirectoryName(projectFile); var testItems = new HashSet <string>(StringComparer.OrdinalIgnoreCase); var testFolder = Path.Combine(projectHome, testRoot); if (!Directory.Exists(testFolder)) { logger.SendMessage(TestMessageLevel.Warning, $"Test folder path '{testFolder}' doesn't exist."); continue; } // grab all files, we try for .ts files first, and only parse the .js files if we don't find any foreach (var file in Directory.EnumerateFiles(testFolder, "*.ts", SearchOption.AllDirectories)) { ProcessFiles(file); } if (!testItems.Any()) { foreach (var file in Directory.EnumerateFiles(testFolder, "*.js", SearchOption.AllDirectories)) { ProcessFiles(file); } } if (testItems.Any()) { var testFx = frameworkDiscoverer.GetFramework(testFramework); if (testFx == null) { logger.SendMessage(TestMessageLevel.Warning, $"Ignoring unsupported test framework '{testFramework}'."); return; } var nodeExePath = Nodejs.GetAbsoluteNodeExePath(projectHome, propertyGroup.Descendants(NodeProjectProperty.NodeExePath).FirstOrDefault()?.Value); if (string.IsNullOrEmpty(nodeExePath)) { // if nothing specified in the project fallback to environment nodeExePath = Nodejs.GetPathToNodeExecutableFromEnvironment(); } this.DiscoverTests(testItems, testFx, discoverySink, logger, nodeExePath, projectFile); } void ProcessFiles(string fileAbsolutePath) { var typeScriptTest = TypeScript.TypeScriptHelpers.IsTypeScriptFile(fileAbsolutePath); if (typeScriptTest) { fileAbsolutePath = TypeScript.TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(projectHome, outDir, fileAbsolutePath); } else if (!StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(fileAbsolutePath), ".js")) { return; } testItems.Add(fileAbsolutePath); } } } catch (Exception ex) { logger.SendMessage(TestMessageLevel.Error, ex.Message); throw; } }
internal void DiscoverTestFiles(string packageJsonPath, IMessageLogger logger, ITestCaseDiscoverySink discoverySink) { logger.SendMessage(TestMessageLevel.Informational, $"Parsing '{packageJsonPath}'."); var packageJson = PackageJsonFactory.Create(packageJsonPath); if (string.IsNullOrEmpty(packageJson.TestRoot)) { logger.SendMessage(TestMessageLevel.Informational, "No vsTestOptions|testRoot specified."); return; } var workingDir = Path.GetDirectoryName(packageJsonPath); var testFolderPath = Path.Combine(workingDir, packageJson.TestRoot); if (!Directory.Exists(testFolderPath)) { logger.SendMessage(TestMessageLevel.Error, $"Testroot '{packageJson.TestRoot}' doesn't exist."); return; } TestFramework testFx = null; foreach (var dep in packageJson.AllDependencies) { testFx = FrameworkDiscoverer.Instance.Get(dep.Name); if (testFx != null) { break; } } testFx = testFx ?? FrameworkDiscoverer.Instance.Get("ExportRunner"); var nodeExePath = Nodejs.GetPathToNodeExecutableFromEnvironment(); if (!File.Exists(nodeExePath)) { logger.SendMessage(TestMessageLevel.Error, "Node.exe was not found. Please install Node.js before running tests."); return; } var fileList = Directory.GetFiles(testFolderPath, "*.js", SearchOption.AllDirectories); var files = string.Join(";", fileList); logger.SendMessage(TestMessageLevel.Informational, $"Processing: {files}"); var discoveredTestCases = testFx.FindTests(fileList, nodeExePath, logger, projectRoot: workingDir); if (!discoveredTestCases.Any()) { logger.SendMessage(TestMessageLevel.Warning, "Discovered 0 testcases."); return; } foreach (var discoveredTest in discoveredTestCases) { var qualifiedName = discoveredTest.FullyQualifiedName; const string indent = " "; logger.SendMessage(TestMessageLevel.Informational, $"{indent}Creating TestCase:{qualifiedName}"); //figure out the test source info such as line number var filePath = CommonUtils.GetAbsoluteFilePath(workingDir, discoveredTest.TestFile); var testcase = new TestCase(qualifiedName, NodejsConstants.PackageJsonExecutorUri, packageJsonPath) { CodeFilePath = filePath, LineNumber = discoveredTest.SourceLine, DisplayName = discoveredTest.TestName }; testcase.SetPropertyValue(JavaScriptTestCaseProperties.TestFramework, testFx.Name); testcase.SetPropertyValue(JavaScriptTestCaseProperties.WorkingDir, workingDir); testcase.SetPropertyValue(JavaScriptTestCaseProperties.ProjectRootDir, workingDir); testcase.SetPropertyValue(JavaScriptTestCaseProperties.NodeExePath, nodeExePath); testcase.SetPropertyValue(JavaScriptTestCaseProperties.TestFile, filePath); discoverySink.SendTestCase(testcase); } logger.SendMessage(TestMessageLevel.Informational, $"Processing finished for framework '{testFx.Name}'."); }
public async Task <ExecutionResult> Execute(IReplWindow window, string arguments) { string projectPath = string.Empty; string npmArguments = arguments.Trim(' ', '\t'); // Parse project name/directory in square brackets if (npmArguments.StartsWith("[", StringComparison.Ordinal)) { var match = Regex.Match(npmArguments, @"(?:[[]\s*\""?\s*)(.*?)(?:\s*\""?\s*[]]\s*)"); projectPath = match.Groups[1].Value; npmArguments = npmArguments.Substring(match.Length); } // Include spaces on either side of npm arguments so that we can more simply detect arguments // at beginning and end of string (e.g. '--global') npmArguments = string.Format(CultureInfo.InvariantCulture, " {0} ", npmArguments); // Prevent running `npm init` without the `-y` flag since it will freeze the repl window, // waiting for user input that will never come. if (npmArguments.Contains(" init ") && !(npmArguments.Contains(" -y ") || npmArguments.Contains(" --yes "))) { window.WriteError(SR.GetString(SR.ReplWindowNpmInitNoYesFlagWarning)); return(ExecutionResult.Failure); } var solution = Package.GetGlobalService(typeof(SVsSolution)) as IVsSolution; IEnumerable <IVsProject> loadedProjects = solution.EnumerateLoadedProjects(onlyNodeProjects: false); var projectNameToDirectoryDictionary = new Dictionary <string, Tuple <string, IVsHierarchy> >(StringComparer.OrdinalIgnoreCase); foreach (IVsProject project in loadedProjects) { var hierarchy = (IVsHierarchy)project; object extObject; var projectResult = hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out extObject); if (!ErrorHandler.Succeeded(projectResult)) { continue; } EnvDTE.Project dteProject = extObject as EnvDTE.Project; if (dteProject == null) { continue; } string projectName = dteProject.Name; if (string.IsNullOrEmpty(projectName)) { continue; } // Try checking the `ProjectHome` property first EnvDTE.Properties properties = dteProject.Properties; if (dteProject.Properties != null) { EnvDTE.Property projectHome = null; try { projectHome = properties.Item("ProjectHome"); } catch (ArgumentException) { // noop } if (projectHome != null) { var projectHomeDirectory = projectHome.Value as string; if (!string.IsNullOrEmpty(projectHomeDirectory)) { projectNameToDirectoryDictionary.Add(projectName, Tuple.Create(projectHomeDirectory, hierarchy)); continue; } } } // Otherwise, fall back to using fullname string projectDirectory = string.IsNullOrEmpty(dteProject.FullName) ? null : Path.GetDirectoryName(dteProject.FullName); if (!string.IsNullOrEmpty(projectDirectory)) { projectNameToDirectoryDictionary.Add(projectName, Tuple.Create(projectDirectory, hierarchy)); } } Tuple <string, IVsHierarchy> projectInfo; if (string.IsNullOrEmpty(projectPath) && projectNameToDirectoryDictionary.Count == 1) { projectInfo = projectNameToDirectoryDictionary.Values.First(); } else { projectNameToDirectoryDictionary.TryGetValue(projectPath, out projectInfo); } NodejsProjectNode nodejsProject = null; if (projectInfo != null) { projectPath = projectInfo.Item1; if (projectInfo.Item2 != null) { nodejsProject = projectInfo.Item2.GetProject().GetNodejsProject(); } } bool isGlobalCommand = false; if (string.IsNullOrWhiteSpace(npmArguments) || npmArguments.Contains(" -g ") || npmArguments.Contains(" --global ")) { projectPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); isGlobalCommand = true; } // In case someone copies filename string projectDirectoryPath = File.Exists(projectPath) ? Path.GetDirectoryName(projectPath) : projectPath; if (!isGlobalCommand && !Directory.Exists(projectDirectoryPath)) { window.WriteError("Please specify a valid Node.js project or project directory. If your solution contains multiple projects, specify a target project using .npm [ProjectName or ProjectDir] <npm arguments> For example: .npm [MyApp] list"); return(ExecutionResult.Failure); } string npmPath; try { npmPath = NpmHelpers.GetPathToNpm( nodejsProject != null ? Nodejs.GetAbsoluteNodeExePath( nodejsProject.ProjectHome, nodejsProject.GetProjectProperty(NodeProjectProperty.NodeExePath)) : null); } catch (NpmNotFoundException) { Nodejs.ShowNodejsNotInstalled(); return(ExecutionResult.Failure); } var npmReplRedirector = new NpmReplRedirector(window); await ExecuteNpmCommandAsync( npmReplRedirector, npmPath, projectDirectoryPath, new[] { npmArguments }, null); if (npmReplRedirector.HasErrors) { window.WriteError(SR.GetString(SR.NpmReplCommandCompletedWithErrors, arguments)); } else { window.WriteLine(SR.GetString(SR.NpmSuccessfullyCompleted, arguments)); } if (nodejsProject != null) { await nodejsProject.CheckForLongPaths(npmArguments); } return(ExecutionResult.Success); }
private void DiscoverTests(Dictionary <string, List <TestFileEntry> > testItems, MSBuild.Project proj, ITestCaseDiscoverySink discoverySink, IMessageLogger logger) { var result = new List <TestFrameworks.NodejsTestInfo>(); var projectHome = Path.GetFullPath(Path.Combine(proj.DirectoryPath, ".")); var projSource = proj.FullPath; var nodeExePath = Nodejs.GetAbsoluteNodeExePath( projectHome, proj.GetPropertyValue(NodeProjectProperty.NodeExePath)); if (!File.Exists(nodeExePath)) { logger.SendMessage(TestMessageLevel.Error, string.Format(CultureInfo.CurrentCulture, "Node.exe was not found. Please install Node.js before running tests.")); return; } var testCount = 0; foreach (var testFx in testItems.Keys) { var testFramework = GetTestFrameworkObject(testFx); if (testFramework == null) { logger.SendMessage(TestMessageLevel.Warning, string.Format(CultureInfo.CurrentCulture, "Ignoring unsupported test framework {0}", testFx)); continue; } var fileList = testItems[testFx]; var files = string.Join(";", fileList.Select(p => p.File)); logger.SendMessage(TestMessageLevel.Informational, string.Format(CultureInfo.CurrentCulture, "Processing: {0}", files)); var discoveredTestCases = testFramework.FindTests(fileList.Select(p => p.File), nodeExePath, logger, projectHome); testCount += discoveredTestCases.Count; foreach (var discoveredTest in discoveredTestCases) { var qualifiedName = discoveredTest.FullyQualifiedName; logger.SendMessage(TestMessageLevel.Informational, string.Format(CultureInfo.CurrentCulture, " " /*indent*/ + "Creating TestCase:{0}", qualifiedName)); //figure out the test source info such as line number var filePath = discoveredTest.ModulePath; var entry = fileList.Find(p => p.File.Equals(filePath, StringComparison.OrdinalIgnoreCase)); FunctionInformation fi = null; if (entry.IsTypeScriptTest) { fi = SourceMapper.MaybeMap(new FunctionInformation(string.Empty, discoveredTest.TestName, discoveredTest.SourceLine, entry.File)); } discoverySink.SendTestCase( new TestCase(qualifiedName, TestExecutor.ExecutorUri, projSource) { CodeFilePath = (fi != null) ? fi.Filename : filePath, LineNumber = (fi != null && fi.LineNumber.HasValue) ? fi.LineNumber.Value : discoveredTest.SourceLine, DisplayName = discoveredTest.TestName }); } logger.SendMessage(TestMessageLevel.Informational, string.Format(CultureInfo.CurrentCulture, "Processing finished for framework of {0}", testFx)); } if (testCount == 0) { logger.SendMessage(TestMessageLevel.Warning, string.Format(CultureInfo.CurrentCulture, "Discovered 0 testcases.")); } }
private string GetNodePath() { var overridePath = this._project.GetProjectProperty(NodeProjectProperty.NodeExePath); return(Nodejs.GetAbsoluteNodeExePath(this._project.ProjectHome, overridePath)); }
/// <summary> /// ITestDiscover, Given a list of test sources this method pulls out the test cases /// </summary> /// <param name="sources">List of test sources passed from client (Client can be VS or command line)</param> /// <param name="logger">Used to relay messages to registered loggers</param> /// <param name="discoverySink">Callback used to notify client upon discovery of test cases</param> private void DiscoverTestsCore(IEnumerable <string> sources, IMessageLogger logger, ITestCaseDiscoverySink discoverySink) { ValidateArg.NotNull(sources, nameof(sources)); ValidateArg.NotNull(discoverySink, nameof(discoverySink)); ValidateArg.NotNull(logger, nameof(logger)); var env = new Dictionary <string, string>(); var root = Environment.GetEnvironmentVariable("VSINSTALLDIR"); #if DEBUG logger.SendMessage(TestMessageLevel.Informational, $"VSINSTALLDIR: {root}"); #endif if (!string.IsNullOrEmpty(root)) { env["VsInstallRoot"] = root; env["MSBuildExtensionsPath32"] = Path.Combine(root, "MSBuild"); } using (var buildEngine = new MSBuild.ProjectCollection(env)) { try { // Load all the test containers passed in (.njsproj msbuild files) foreach (var source in sources) { var cleanPath = source.Trim('\'', '"'); buildEngine.LoadProject(cleanPath); } FrameworkDiscoverer frameworkDiscoverer = null; foreach (var proj in buildEngine.LoadedProjects) { var projectHome = Path.GetFullPath(Path.Combine(proj.DirectoryPath, ".")); var testItems = TestFrameworkFactory.GetTestItems(projectHome, proj); if (testItems.Any()) { frameworkDiscoverer = frameworkDiscoverer ?? new FrameworkDiscoverer(); var nodeExePath = Nodejs.GetAbsoluteNodeExePath(projectHome, proj.GetPropertyValue(NodeProjectProperty.NodeExePath)); if (string.IsNullOrEmpty(nodeExePath)) { // if nothing specified in the project fallback to environment nodeExePath = Nodejs.GetPathToNodeExecutableFromEnvironment(); } this.DiscoverTests(testItems, frameworkDiscoverer, discoverySink, logger, nodeExePath, proj.FullPath); } } } catch (Exception ex) { logger.SendMessage(TestMessageLevel.Error, ex.Message); throw; } finally { // Disposing buildEngine does not clear the document cache in // VS 2013, so manually unload all projects before disposing. buildEngine.UnloadAllProjects(); } } }
private string GetNodePath() { var overridePath = _project.GetProjectProperty(NodejsConstants.NodeExePath); return(Nodejs.GetAbsoluteNodeExePath(_project.ProjectHome, overridePath)); }
private void RunTestCases(IEnumerable <TestCase> tests, IRunContext runContext, IFrameworkHandle frameworkHandle, NodejsProjectSettings settings) { // May be null, but this is handled by RunTestCase if it matters. // No VS instance just means no debugging, but everything else is // okay. if (tests.Count() == 0) { return; } using (var app = VisualStudioApp.FromEnvironmentVariable(NodejsConstants.NodeToolsProcessIdEnvironmentVariable)) { var port = 0; var nodeArgs = new List <string>(); // .njsproj file path -> project settings var sourceToSettings = new Dictionary <string, NodejsProjectSettings>(); var testObjects = new List <TestCaseObject>(); if (!File.Exists(settings.NodeExePath)) { frameworkHandle.SendMessage(TestMessageLevel.Error, "Interpreter path does not exist: " + settings.NodeExePath); return; } // All tests being run are for the same test file, so just use the first test listed to get the working dir var testInfo = new NodejsTestInfo(tests.First().FullyQualifiedName); var workingDir = Path.GetDirectoryName(CommonUtils.GetAbsoluteFilePath(settings.WorkingDir, testInfo.ModulePath)); var nodeVersion = Nodejs.GetNodeVersion(settings.NodeExePath); // We can only log telemetry when we're running in VS. // Since the required assemblies are not on disk if we're not running in VS, we have to reference them in a separate method // this way the .NET framework only tries to load the assemblies when we actually need them. if (app != null) { LogTelemetry(tests.Count(), nodeVersion, runContext.IsBeingDebugged); } foreach (var test in tests) { if (_cancelRequested.WaitOne(0)) { break; } if (settings == null) { frameworkHandle.SendMessage( TestMessageLevel.Error, $"Unable to determine interpreter to use for {test.Source}."); frameworkHandle.RecordEnd(test, TestOutcome.Failed); } var args = new List <string>(); args.AddRange(GetInterpreterArgs(test, workingDir, settings.ProjectRootDir)); // Fetch the run_tests argument for starting node.exe if not specified yet if (nodeArgs.Count == 0 && args.Count > 0) { nodeArgs.Add(args[0]); } testObjects.Add(new TestCaseObject(args[1], args[2], args[3], args[4], args[5])); } if (runContext.IsBeingDebugged && app != null) { app.GetDTE().Debugger.DetachAll(); // Ensure that --debug-brk is the first argument nodeArgs.InsertRange(0, GetDebugArgs(out port)); } _nodeProcess = ProcessOutput.Run( settings.NodeExePath, nodeArgs, settings.WorkingDir, /* env */ null, /* visible */ false, /* redirector */ new TestExecutionRedirector(this.ProcessTestRunnerEmit), /* quote args */ false); if (runContext.IsBeingDebugged && app != null) { try { //the '#ping=0' is a special flag to tell VS node debugger not to connect to the port, //because a connection carries the consequence of setting off --debug-brk, and breakpoints will be missed. var qualifierUri = string.Format("tcp://localhost:{0}#ping=0", port); while (!app.AttachToProcess(_nodeProcess, NodejsRemoteDebugPortSupplierUnsecuredId, qualifierUri)) { if (_nodeProcess.Wait(TimeSpan.FromMilliseconds(500))) { break; } } #if DEBUG } catch (COMException ex) { frameworkHandle.SendMessage(TestMessageLevel.Error, "Error occurred connecting to debuggee."); frameworkHandle.SendMessage(TestMessageLevel.Error, ex.ToString()); KillNodeProcess(); } #else } catch (COMException) {
private void RunTestCases(IEnumerable <TestCaseResult> tests) { // May be null, but this is handled by RunTestCase if it matters. // No VS instance just means no debugging, but everything else is okay. if (!tests.Any()) { return; } var startedFromVs = this.HasVisualStudioProcessId(out var vsProcessId); var nodeArgs = new List <string>(); var testObjects = new List <TestCaseObject>(); // All tests being run are for the same test file, so just use the first test listed to get the working dir var firstTest = tests.First().TestCase; var testFramework = firstTest.GetPropertyValue(JavaScriptTestCaseProperties.TestFramework, defaultValue: TestFrameworkDirectories.ExportRunnerFrameworkName); var workingDir = firstTest.GetPropertyValue(JavaScriptTestCaseProperties.WorkingDir, defaultValue: Path.GetDirectoryName(firstTest.CodeFilePath)); var nodeExePath = firstTest.GetPropertyValue <string>(JavaScriptTestCaseProperties.NodeExePath, defaultValue: null); var projectRootDir = firstTest.GetPropertyValue(JavaScriptTestCaseProperties.ProjectRootDir, defaultValue: Path.GetDirectoryName(firstTest.CodeFilePath)); if (string.IsNullOrEmpty(nodeExePath) || !File.Exists(nodeExePath)) { this.frameworkHandle.SendMessage(TestMessageLevel.Error, "Interpreter path does not exist: " + nodeExePath); return; } var nodeVersion = Nodejs.GetNodeVersion(nodeExePath); foreach (var test in tests) { if (this.cancelRequested.WaitOne(0)) { break; } var args = this.GetInterpreterArgs(test.TestCase, workingDir, projectRootDir); // Fetch the run_tests argument for starting node.exe if not specified yet if (!nodeArgs.Any()) { nodeArgs.Add(args.RunTestsScriptFile); } testObjects.Add(new TestCaseObject( framework: args.TestFramework, fullyQualifiedName: args.fullyQualifiedName, testFile: args.TestFile, workingFolder: args.WorkingDirectory, projectFolder: args.ProjectRootDir)); } var port = 0; if (this.runContext.IsBeingDebugged && startedFromVs) { this.DetachDebugger(vsProcessId); // Ensure that --debug-brk or --inspect-brk is the first argument nodeArgs.Insert(0, GetDebugArgs(nodeVersion, out port)); } // make sure the tests completed is not signalled. this.testsCompleted.Reset(); this.nodeProcess = ProcessOutput.Run( nodeExePath, nodeArgs, workingDir, env: null, visible: false, redirector: new TestExecutionRedirector(this.ProcessTestRunnerEmit), quoteArgs: false); if (this.runContext.IsBeingDebugged && startedFromVs) { this.AttachDebugger(vsProcessId, port, nodeVersion); } var serializedObjects = JsonConvert.SerializeObject(testObjects); // Send the process the list of tests to run and wait for it to complete this.nodeProcess.WriteInputLine(serializedObjects); // for node 8 the process doesn't automatically exit when debugging, so always detach WaitHandle.WaitAny(new[] { this.nodeProcess.WaitHandle, this.testsCompleted }); if (this.runContext.IsBeingDebugged && startedFromVs) { this.DetachDebugger(vsProcessId); } // Automatically fail tests that haven't been run by this point (failures in before() hooks) foreach (var notRunTest in this.currentTests) { var result = new TestResult(notRunTest.TestCase) { Outcome = TestOutcome.Failed }; if (this.currentResultObject != null) { result.Messages.Add(new TestResultMessage(TestResultMessage.StandardOutCategory, this.currentResultObject.stdout)); result.Messages.Add(new TestResultMessage(TestResultMessage.StandardErrorCategory, this.currentResultObject.stderr)); } this.frameworkHandle.RecordResult(result); this.frameworkHandle.RecordEnd(notRunTest.TestCase, TestOutcome.Failed); } }