extent-framework/extentreports-csharp

Missing detailed test results with a XML file ( but not the other)

Opened this issue · 1 comments

I've tested this in ExtentReports 4.1.0.0

For some reason, the ExtentReports is missing detailed test results with one XML (Nunit3mits2testresult.xml), but not the other (Nunit3sidetestresult.xml).

Here are the screenshots, notice the glaring difference in the RHS panels:

Nunit3mits2testresult

Nunit3sidetestresult

Here's my code:

    /// <summary>
    /// 
    /// </summary>
    /// <param name="testResultsFilePath">The XML file</param>
    /// <param name="htmlDirectory">Folder path</param>
    /// <returns></returns>
    public void ProcessSingle(string testResultsFilePath, string htmlDirectory)
    {
        var _extent = new ExtentReports();

        var output = htmlDirectory.EndsWith("\\") || htmlDirectory.EndsWith("/") ? htmlDirectory : htmlDirectory + "\\";
        _extent.AttachReporter(new ExtentHtmlReporter(output));

        new NUnitParser(_extent).ParseTestRunnerOutput(testResultsFilePath);
        _extent.Flush();
    }


internal class NUnitParser
{
    private ExtentReports _extent;

    public NUnitParser(ExtentReports extent)
    {
        _extent = extent;
    }

    public void ParseTestRunnerOutput(string resultsFile)
    {
        var doc = XDocument.Load(resultsFile);
        DateTime timeStampParsed;

        if (doc.Root == null)
        {
            throw new NullReferenceException("Root element not found for " + resultsFile);
        }

        AddSystemInformation(doc);

        var suites = doc
            .Descendants("test-suite")
            .Where(x => x.Attribute("type").Value.Equals("TestFixture", StringComparison.CurrentCultureIgnoreCase));

        foreach (var ts in suites.ToList())
        {
            var test = _extent.CreateTest(ts.Attribute("name").Value);

            // any error messages and/or stack-trace
            var failure = ts.Element("failure");
            if (failure != null)
            {
                var message = failure.Element("message");
                if (message != null)
                {
                    test.Fail(message.Value);
                }

                var stacktrace = failure.Element("stack-trace");
                if (stacktrace != null && !string.IsNullOrWhiteSpace(stacktrace.Value))
                {
                    test.Fail(MarkupHelper.CreateCodeBlock(stacktrace.Value));
                }
            }

            var output = ts.Element("output")?.Value;
            if (!string.IsNullOrWhiteSpace(output))
            {
                test.Info(output);
            }

            // get test suite level categories
            var suiteCategories = ParseTags(ts, false);

            // Test Cases
            foreach (var tc in ts.Descendants("test-case").ToList())
            {
                var node = CreateNode(tc, test);

                AssignStatusAndMessage(tc, node);
                AssignTags(tc, node);

                if (tc.Attribute("start-time") != null)
                {
                    DateTime.TryParse(tc.Attribute("start-time").Value, out timeStampParsed);
                    node.Model.StartTime = timeStampParsed;
                }
                if (tc.Attribute("end-time") != null)
                {
                    DateTime.TryParse(tc.Attribute("end-time").Value, out timeStampParsed);
                    node.Model.EndTime = timeStampParsed;
                }
            }
        }
    }

    private static ExtentTest CreateNode(XElement tc, ExtentTest test)
    {
        var name = tc.Attribute("name").Value;
        var descriptions =
            tc.Descendants("property")
            .Where(c => c.Attribute("name").Value.Equals("Description", StringComparison.CurrentCultureIgnoreCase));
        var description = descriptions.Any() ? descriptions.ToArray()[0].Attribute("value").Value : string.Empty;
        var node = test.CreateNode(name, description);
        return node;
    }

    private static void AssignStatusAndMessage(XElement tc, ExtentTest test)
    {
        var status = StatusExtensions.ToStatus(tc.Attribute("result").Value);

        // error and other status messages
        var statusMessage = tc.Element("failure") != null && tc.Element("failure").Element("message") != null ? tc.Element("failure").Element("message").Value.Trim() : string.Empty;
        statusMessage += tc.Element("failure") != null && tc.Element("failure").Element("stack-trace") != null ? tc.Element("failure").Element("stack-trace").Value.Trim() : string.Empty;
        statusMessage += tc.Element("reason") != null && tc.Element("reason").Element("message") != null ? tc.Element("reason").Element("message").Value.Trim() : string.Empty;
        statusMessage += tc.Element("output") != null ? tc.Element("output").Value.Trim() : string.Empty;
        statusMessage = (status == Status.Fail || status == Status.Error) ? MarkupHelper.CreateCodeBlock(statusMessage).GetMarkup() : statusMessage;
        statusMessage = string.IsNullOrEmpty(statusMessage) ? status.ToString() : statusMessage;
        test.Log(status, statusMessage);
    }

    private static void AssignTags(XElement tc, ExtentTest test)
    {
        // get test case level categories
        var categories = ParseTags(tc, true);

        // if this is a parameterized test, get the categories from the parent test-suite
        var parameterizedTestElement = tc
            .Ancestors("test-suite").ToList()
            .Where(x => x.Attribute("type").Value.Equals("ParameterizedTest", StringComparison.CurrentCultureIgnoreCase))
            .FirstOrDefault();

        if (null != parameterizedTestElement)
        {
            var paramCategories = ParseTags(parameterizedTestElement, false);
            categories.UnionWith(paramCategories);
        }

        categories.ToList().ForEach(x => test.AssignCategory(x));
    }

    private static HashSet<string> ParseTags(XElement elem, bool allDescendents)
    {
        var parser = allDescendents
            ? new Func<XElement, string, IEnumerable<XElement>>((e, s) => e.Descendants(s))
            : new Func<XElement, string, IEnumerable<XElement>>((e, s) => e.Elements(s));

        var categories = new HashSet<string>();
        if (parser(elem, "categories").Any())
        {
            var tags = parser(elem, "categories").Elements("category").ToList();
            tags.ForEach(x => categories.Add(x.Attribute("name").Value));
        }

        return categories;
    }

    private void AddSystemInformation(XDocument doc)
    {
        if (doc.Descendants("environment") == null)
            return;

        var env = doc.Descendants("environment").FirstOrDefault();
        if (env == null)
            return;

        if (env.Attribute("os-version") != null)
            _extent.AddSystemInfo("NUnit Version", env.Attribute("os-version").Value);
        if (env.Attribute("os-version") != null)
            _extent.AddSystemInfo("OS Version", env.Attribute("os-version").Value);
        if (env.Attribute("platform") != null)
            _extent.AddSystemInfo("Platform", env.Attribute("platform").Value);
        if (env.Attribute("clr-version") != null)
            _extent.AddSystemInfo("CLR Version", env.Attribute("clr-version").Value);
        if (env.Attribute("machine-name") != null)
            _extent.AddSystemInfo("Machine Name", env.Attribute("machine-name").Value);
        if (env.Attribute("user") != null)
            _extent.AddSystemInfo("User", env.Attribute("user").Value);
        if (env.Attribute("user-domain") != null)
            _extent.AddSystemInfo("User Domain", env.Attribute("user-domain").Value);
    }
}

Because the above code works with one XML but not the other, that's why I think it's a bug.

Here are the zip file that contains the above two XMLs. xml.zip

I have the same issue here:
image
These are the details:

  • HTML Report
  • Intermittent issue
  • It happens more often on UI tests running in parallel with Playwright+Webkit
  • Also the dashboard is empty