Repository: mochajs/mocha

Problem statement:
🚀 Feature: Add file path to xunit reporter
### Feature Request Checklist

- [X] I have read and agree to Mocha's [Code of Conduct](https://github.com/mochajs/mocha/blob/master/.github/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/mochajs/mocha/blob/master/.github/CONTRIBUTING.md)
- [X] I have searched for [related issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue) and [issues with the `faq` label](https://github.com/mochajs/mocha/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Afaq%20), but none matched my issue.
- [X] I want to provide a PR to resolve this

### Overview

Filing an issue to track #4985: back in #4219, the `json`, `doc`, and `json-stream` reporters were augmented to output the test filenames in addition to their other attributes. But the `xunit` reporter wasn't given the same addition.

### Suggested Solution

#4985, literally. 😄 

As in: adding `file: test.file` to the reported attributes.

### Alternatives

I can't think of anything. https://github.com/mochajs/mocha/pull/4985/files#r1193989943 suggests using `test?.invocationDetails?.absoluteFile` as a backup, but neither `invocationDetails` nor `absoluteFile` exist in Mocha. I think that's a Cypress-only thing.

### Additional Info

Adding a co-author credit as @bmish made two PRs justifying this feature. ❤️ 

Co-authored-by: @bmish


Hints:

Patch:
diff --git a/lib/reporters/xunit.js b/lib/reporters/xunit.js
--- a/lib/reporters/xunit.js
+++ b/lib/reporters/xunit.js
@@ -158,6 +158,7 @@ XUnit.prototype.test = function (test) {
   var attrs = {
     classname: test.parent.fullTitle(),
     name: test.title,
+    file: test.file,
     time: test.duration / 1000 || 0
   };
 


Test patch:
diff --git a/test/reporters/xunit.spec.js b/test/reporters/xunit.spec.js
--- a/test/reporters/xunit.spec.js
+++ b/test/reporters/xunit.spec.js
@@ -30,6 +30,7 @@ describe('XUnit reporter', function () {
   var expectedLine = 'some-line';
   var expectedClassName = 'fullTitle';
   var expectedTitle = 'some title';
+  var expectedFile = 'testFile.spec.js';
   var expectedMessage = 'some message';
   var expectedDiff =
     '\n      + expected - actual\n\n      -foo\n      +bar\n      ';
@@ -325,6 +326,7 @@ describe('XUnit reporter', function () {
         var expectedTest = {
           state: STATE_FAILED,
           title: expectedTitle,
+          file: expectedFile,
           parent: {
             fullTitle: function () {
               return expectedClassName;
@@ -347,6 +349,8 @@ describe('XUnit reporter', function () {
           expectedClassName +
           '" name="' +
           expectedTitle +
+          '" file="' +
+          expectedFile +
           '" time="1"><failure>' +
           expectedMessage +
           '\n' +
@@ -365,6 +369,7 @@ describe('XUnit reporter', function () {
         var expectedTest = {
           state: STATE_FAILED,
           title: expectedTitle,
+          file: expectedFile,
           parent: {
             fullTitle: function () {
               return expectedClassName;
@@ -402,6 +407,7 @@ describe('XUnit reporter', function () {
             return true;
           },
           title: expectedTitle,
+          file: expectedFile,
           parent: {
             fullTitle: function () {
               return expectedClassName;
@@ -418,6 +424,8 @@ describe('XUnit reporter', function () {
           expectedClassName +
           '" name="' +
           expectedTitle +
+          '" file="' +
+          expectedFile +
           '" time="1"><skipped/></testcase>';
         expect(expectedWrite, 'to be', expectedTag);
       });
@@ -431,6 +439,7 @@ describe('XUnit reporter', function () {
             return false;
           },
           title: expectedTitle,
+          file: expectedFile,
           parent: {
             fullTitle: function () {
               return expectedClassName;
@@ -447,6 +456,8 @@ describe('XUnit reporter', function () {
           expectedClassName +
           '" name="' +
           expectedTitle +
+          '" file="' +
+          expectedFile +
           '" time="0"/>';
         expect(expectedWrite, 'to be', expectedTag);
       });