private static (string, string)? GetTestFrameworkAndFilePath(Project project, ProjectItem projectItem, string projectRoot) { var testRoot = project.GetProperty(NodeProjectProperty.TestRoot)?.EvaluatedValue; var testFrameworkName = project.GetProperty(NodeProjectProperty.TestFramework)?.EvaluatedValue; string fileAbsolutePath; if (!string.IsNullOrEmpty(testRoot) && !string.IsNullOrEmpty(testFrameworkName)) // If the test root and framework have been configured on the project. { var testRootPath = Path.GetFullPath(Path.Combine(project.DirectoryPath, testRoot)); try { fileAbsolutePath = CommonUtils.GetAbsoluteFilePath(projectRoot, projectItem.EvaluatedInclude); } catch (ArgumentException) { // .Net core projects include invalid paths, ignore them and continue checking the items. return(null); } if (!fileAbsolutePath.StartsWith(testRootPath, StringComparison.OrdinalIgnoreCase)) { return(null); } } else // If the file has been configured individually. { testFrameworkName = projectItem.GetMetadataValue("TestFramework"); if (!TestFramework.IsValidTestFramework(testFrameworkName)) { return(null); } fileAbsolutePath = CommonUtils.GetAbsoluteFilePath(projectRoot, projectItem.EvaluatedInclude); } // Check if file is a typecript file. If so, get the javascript file. The javascript file needs to be in the same path and name. // It doesn't work with bundlers or minimizers. Also, project needs to be build in order to have the js file created. var typeScriptTest = TypeScriptHelpers.IsTypeScriptFile(fileAbsolutePath); if (typeScriptTest) { fileAbsolutePath = TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(project, fileAbsolutePath); } else if (!StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(fileAbsolutePath), ".js")) { return(null); } return(testFrameworkName, fileAbsolutePath); }
/// <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 = new Dictionary <string, HashSet <string> >(StringComparer.OrdinalIgnoreCase); var testRoot = proj.GetProperty(NodeProjectProperty.TestRoot)?.EvaluatedValue; var testFramework = proj.GetProperty(NodeProjectProperty.TestFramework)?.EvaluatedValue; if (!string.IsNullOrEmpty(testRoot) && string.IsNullOrEmpty(testFramework)) { logger.SendMessage(TestMessageLevel.Warning, $"TestRoot specified for '{Path.GetFileName(proj.FullPath)}' but no TestFramework."); } // Provide all files to the test analyzer foreach (var item in proj.Items) { string testFrameworkName; string fileAbsolutePath; if (!string.IsNullOrEmpty(testRoot) && !string.IsNullOrEmpty(testFramework)) { testFrameworkName = testFramework; var testRootPath = Path.GetFullPath(Path.Combine(proj.DirectoryPath, testRoot)); try { fileAbsolutePath = CommonUtils.GetAbsoluteFilePath(projectHome, item.EvaluatedInclude); } catch (ArgumentException) { // .Net core projects include invalid paths, ignore them and continue checking the items. continue; } if (!fileAbsolutePath.StartsWith(testRootPath, StringComparison.OrdinalIgnoreCase)) { continue; } } else { //Check to see if this is a TestCase testFrameworkName = item.GetMetadataValue("TestFramework"); if (!TestFramework.IsValidTestFramework(testFrameworkName)) { continue; } fileAbsolutePath = CommonUtils.GetAbsoluteFilePath(projectHome, item.EvaluatedInclude); } var typeScriptTest = TypeScript.TypeScriptHelpers.IsTypeScriptFile(fileAbsolutePath); if (typeScriptTest) { fileAbsolutePath = TypeScript.TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(proj, fileAbsolutePath); } else if (!StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(fileAbsolutePath), ".js")) { continue; } if (!testItems.TryGetValue(testFrameworkName, out var fileList)) { fileList = new HashSet <string>(StringComparer.OrdinalIgnoreCase); testItems.Add(testFrameworkName, fileList); } fileList.Add(fileAbsolutePath); } 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(); } } }