Example #1
0
        // use map file to get TS source file pos from JS file pos
        private static SourcePos FindTypeScriptLineNumber(string soureMapFile, SourcePos jsOneBasedSourcePos)
        {
            // convert to zero-based coords
            SourcePosition jsZeroBasedSourcePos = jsOneBasedSourcePos.GetZeroBasedPosition();

            // Parse the source map from file
            SourceMapParser parser = new SourceMapParser();
            SourceMap       sourceMap;

            using (FileStream stream = new FileStream(soureMapFile, FileMode.Open))
            {
                sourceMap = parser.ParseSourceMap(new StreamReader(stream));
            }

            // look for JS source position in map entries
            // if we can't find the exact location in the map file, we get a null result, so to safeguard against this happening,
            // we'll look 10 chars either side of the specfied column, and take the closest match if we can't find an exact match
            // if that also fails, we return notFound = [0,0] = line 1, column 1
            // (column is not currently used, but required to get the mapped line number)
            MappingEntry[] mapEntry = new MappingEntry[3];
            for (int delta = 0; delta <= 10; delta++)
            {
                SourcePosition posBefore = jsZeroBasedSourcePos;
                posBefore.ZeroBasedColumnNumber -= delta;

                SourcePosition posAfter = jsZeroBasedSourcePos;
                posAfter.ZeroBasedColumnNumber += delta;

                mapEntry[0] = sourceMap.GetMappingEntryForGeneratedSourcePosition(jsZeroBasedSourcePos);
                mapEntry[1] = sourceMap.GetMappingEntryForGeneratedSourcePosition(posBefore);
                mapEntry[2] = sourceMap.GetMappingEntryForGeneratedSourcePosition(posAfter);

                if (mapEntry[0] != null || mapEntry[1] != null || mapEntry[2] != null)
                {
                    break;
                }
            }

            MappingEntry tsMapEnt = null;

            for (int i = 0; i < 3; i++)
            {
                if (mapEntry[i] != null)
                {
                    tsMapEnt = mapEntry[i];
                    break;
                }
            }

            if (tsMapEnt == null)
            {
                Log($"Unable to map Javascript source pos to TypeScript source file, mapping file was: {soureMapFile}");
                return(SourcePos.Notfound);
            }
            else
            {
                Log($"Successfully mapped Javascript source pos to TypeScript pos using mapping file: {soureMapFile}");
                return(new SourcePos(tsMapEnt.OriginalSourcePosition));
            }
        }
Example #2
0
        // extracts location of Javascript error in SpecTest.stackTrace
        private static SourcePos GetJsErrorPosFromStackTrace(string jsFullPathFilename, string stackTrace)
        {
            Log($"Entered GetJsErrorPosFromStackTrace(), tsFullPathFilename = '{jsFullPathFilename}'");

            // first extract JS source file error location from stack trace
            string jsFilename = Path.GetFileName(jsFullPathFilename);
            string pattern    = $"(?<={jsFilename}:)[0-9]+:[0-9]+";           // technically the filename contains '.' chars which should be escaped in regex, but this will still work as '.' matches any char
            Regex  regex      = new Regex(pattern);
            var    match      = regex.Match(stackTrace);

            if (!match.Success)
            {
                Log($"Unable to find JS source file '{jsFilename}' in stack dump {stackTrace}");
                return(SourcePos.Notfound);
            }

            // should now have <line>:<col> in format nnn:nnn
            int    colon     = match.Value.IndexOf(':');
            string jsLineStr = match.Value.Substring(0, colon);
            string jsColStr  = match.Value.Substring(colon + 1);

            SourcePos jsPos = new SourcePos();

            jsPos.Line   = Int32.TryParse(jsLineStr, out jsPos.Line) ? jsPos.Line : 1;
            jsPos.Column = Int32.TryParse(jsColStr, out jsPos.Column) ? jsPos.Column : 1;
            Log($"Found JS source file '{jsFilename}' in stack dump, Javascript error location line={jsPos.Line}, column={jsPos.Column}");

            return(jsPos);
        }
        private TestResult ProcessTsTestResult(TsTestResult tsTestResult, TestCase vsTestCase)
        {
            Log("RunJavaScriptTests() called");

            // init result object
            TestResult vsResult = new TestResult(vsTestCase);

            vsResult.DisplayName  = vsTestCase.DisplayName;
            vsResult.ComputerName = Environment.MachineName;
            vsResult.Outcome      = tsTestResult.testOutcome;
            vsResult.StartTime    = tsTestResult.startTime;
            vsResult.EndTime      = tsTestResult.endTime;
            vsResult.Duration     = new TimeSpan(tsTestResult.durationMs * 10000);

            switch (vsResult.Outcome)
            {
            case TestOutcome.Passed:
                vsResult.ErrorMessage = "Test passed successfully";
                break;

            case TestOutcome.Skipped:
                break;                         // do nothing

            case TestOutcome.None:
                Log($"TestOutcome.None for test {vsResult.TestCase.FullyQualifiedName}");
                break;

            case TestOutcome.NotFound:
                Log($"TestOutcome.NotFound for test {vsResult.TestCase.FullyQualifiedName}");
                break;

            case TestOutcome.Failed:
                // test failed
                vsResult.ErrorMessage    = tsTestResult.errorMessage;
                vsResult.ErrorStackTrace = tsTestResult.errorStackTrace;

                string fullFilename = vsResult.TestCase.Source;
                string filename     = Path.GetFileName(fullFilename);

                // this method can handle both .js and .ts files
                int line = SourcePos.GetErrorPosFromStackTrace(fullFilename, tsTestResult.errorStackTrace).Line;

                // get function name from stack trace
                Regex  regex    = new Regex("[A-Za-z0-9]+");
                Match  match    = regex.Match(vsResult.ErrorStackTrace.Substring(7));
                string function = match.Value;

                // thank-you denvercoder9 (aka Moe Seth)
                // https://social.msdn.microsoft.com/Forums/vstudio/en-US/3be3175d-dce1-48bc-9ffe-10627d99962c/questions-to-unit-test-explorer-gurus-errorstacktrace?forum=vstest
                // "at testMethod1 in C:\TestingProject\UnitTest1\UnitTest1\test.js:line 9"
                vsResult.ErrorStackTrace = $"at {function}() in {fullFilename}:line {line}";
                break;
            }

            Log("...finished checking test results for requested test");

            return(vsResult);
        }
Example #4
0
        // maps location of error in SpecTest.stackTrace from Javascript to TypeScript source file
        private static SourcePos GetTsErrorPosFromStackTrace(string tsFullPathFilename, string stackTrace)
        {
            Log($"Entered GetTsErrorPosFromStackTrace(), tsFullPathFilename = '{tsFullPathFilename}'");

            // first get the location of the error in the Javascript source file from the stack trace
            string    jsFullPathFilename = tsFullPathFilename.Replace(".ts", ".js");
            SourcePos jsPos = GetJsErrorPosFromStackTrace(jsFullPathFilename, stackTrace);

            // check we have a map file available to translate to the the TypeScript source file location
            string mapFilename = $"{jsFullPathFilename}.map";

            if (!File.Exists(mapFilename))
            {
                Log($"Map file {mapFilename} could not be found, cannot translate Javascript error location to TypeScript source location - try rebuilding project to regenerate map file");
                return(SourcePos.Notfound);
            }

            // do the translation
            SourcePos tsOneBasedPos = FindTypeScriptLineNumber(mapFilename, jsPos);

            Log($"Mapped Javscript error location to TypeScript error location: line={tsOneBasedPos.Line}, column={tsOneBasedPos.Column}");

            return(tsOneBasedPos);
        }