public static File saveJunitXml(String targetDir, FeatureResult result, String fileName) {
        DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
        formatter.applyPattern("0.######");
        Document doc = XmlUtils.newDocument();
        Element root = doc.createElement("testsuite");
        doc.appendChild(root);
        root.setAttribute("tests", result.getScenarioCount() + "");
        root.setAttribute("failures", result.getFailedCount() + "");
        root.setAttribute("time", formatter.format(result.getDurationMillis() / 1000));
        root.setAttribute("name", result.getDisplayName()); // will be uri
        root.setAttribute("skipped", "0");
        StringBuilder xmlString = new StringBuilder();
        xmlString.append(XmlUtils.toString(doc, false).replace("/>", ">"));
        String baseName = result.getFeature().getPackageQualifiedName();
        Iterator<ScenarioResult> iterator = result.getScenarioResults().iterator();
        while (iterator.hasNext()) {
            ScenarioResult sr = iterator.next();
            Element testCase = doc.createElement("testcase");
            testCase.setAttribute("classname", baseName);
            StringBuilder sb = new StringBuilder();
            Throwable error = appendSteps(sr.getStepResults(), sb);
            String name = sr.getScenario().getName();
            if (StringUtils.isBlank(name)) {
                name = sr.getScenario().getUniqueId();
            }
            testCase.setAttribute("name", name);
            testCase.setAttribute("time", formatter.format(sr.getDurationMillis() / 1000));
            Element stepsHolder;
            if (error != null) {
                stepsHolder = doc.createElement("failure");
                stepsHolder.setAttribute("message", error.getMessage());
            } else {
                stepsHolder = doc.createElement("system-out");
            }

            Element properties = null;
            properties = addCustomTags(testCase, doc, sr);
            if(properties != null && properties.getChildNodes().getLength() > 0){
                testCase.appendChild(properties);
            }
            
            testCase.appendChild(stepsHolder);
            stepsHolder.setTextContent(sb.toString());
            xmlString.append(XmlUtils.toString(testCase)).append('\n');
        }
        xmlString.append("</testsuite>");
        if (fileName == null) {
            fileName = baseName + ".xml";
        }
        File file = new File(targetDir + File.separator + fileName);
        FileUtils.writeToFile(file, xmlString.toString());
        return file;
    }
@Test
    void testCustomTags() {
        String expectedCustomTags = "<properties><property name=\"requirement\" value=\"CALC-2\"/><property name=\"test_key\" value=\"CALC-2\"/></properties>";
        Feature feature = Feature.read("classpath:com/intuit/karate/report/customTags.feature");
        FeatureRuntime fr = FeatureRuntime.of(new Suite(), new FeatureCall(feature));
        fr.run();
        File file = ReportUtils.saveJunitXml("target", fr.result, null);
        assertTrue(FileUtils.toString(file).contains(expectedCustomTags));
    }