private static List <TestResult> ParseTestResults(HtmlDocument htmlDoc, TestRunMetaData testRunMetaData)
        {
            var cards = htmlDoc.DocumentNode?.SelectNodes("//div[@class='fixtures']//div[@class='card-panel']");

            List <TestResult> results = new List <TestResult>();

            if (cards != null)
            {
                foreach (var card in cards)
                {
                    results.Add(ParseCard(card, testRunMetaData));
                }
            }

            return(results);
        }
        private static TestRun ParseTestRun(HtmlDocument htmlDoc, string shortName)
        {
            try
            {
                var applicationType = ParseApplicationType(htmlDoc);
                var lastRun         = ParseLastRun(htmlDoc);
                var testRunType     = ParseTestRunType(htmlDoc);
                var buildNumber     = ParseBuildNumber(htmlDoc);
                var duration        = ParseDuration(htmlDoc);

                var testRunMetaData = new TestRunMetaData(shortName, applicationType, lastRun, testRunType, buildNumber, duration);
                var results         = ParseTestResults(htmlDoc, testRunMetaData);

                return(new TestRun(testRunMetaData, results));
            }
            catch (Exception e)
            {
                Console.WriteLine($"parse error: {e.Message}, file: {shortName}");
            }

            return(null);
        }
        private static TestResult ParseCard(HtmlNode card, TestRunMetaData testRunMetaData)
        {
            var name            = card.SelectSingleNode(".//span[@class='fixture-name']").InnerText;
            var testResultType  = ParseTestResultType(card);
            var startTimeString = card.SelectSingleNode(".//span[@class='startedAt']").InnerText;
            var endTimeString   = card.SelectSingleNode(".//span[@class='endedAt']").InnerText;
            var startDateTime   = DateTime.Parse(startTimeString);
            var endDateTime     = DateTime.Parse(endTimeString);

            var            subtestNodes = card.SelectNodes(".//div[@class='fixture-content']//table//tr");
            List <SubTest> subTests     = new List <SubTest>();

            foreach (var node in subtestNodes.Skip(1))
            {
                var            subName       = node.SelectSingleNode(".//td[@class='test-name']").InnerText;
                TestResultType subResultType = TestResultType.Passed;
                string         subMessage    = "";

                var failedNode  = node.SelectSingleNode(".//td[@class='failed']");
                var skippedNode = node.SelectSingleNode(".//td[@class='skipped']");

                if (failedNode != null)
                {
                    subResultType = TestResultType.Failed;
                    subMessage    = node.SelectSingleNode(".//td[@class='failed']//pre").InnerText;
                }
                else if (skippedNode != null)
                {
                    subResultType = TestResultType.Skipped;
                    subMessage    = node.SelectSingleNode(".//td[@class='skipped']//pre").InnerText;
                }

                subTests.Add(new SubTest(subName, subResultType, subMessage, subTests.Count));
            }

            return(new TestResult(testRunMetaData, name, testResultType, startDateTime, endDateTime, subTests));
        }