Repository: nodejs/node
File: lib/internal/test_runner/test.js (JavaScript)

Code before:
      // want to force the test runner to exit despite ref'ed handles.
      this.root.run();
    }
  }

  duration() {
    // Duration is recorded in BigInt nanoseconds. Convert to milliseconds.
    return Number(this.endTime - this.startTime) / 1_000_000;
  }

  getReportDetails() {
    let directive;
    const details = { __proto__: null, duration_ms: this.duration() };

    if (this.skipped) {
      directive = this.reporter.getSkip(this.message);
    } else if (this.isTodo) {
      directive = this.reporter.getTodo(this.message);
    } else if (this.expectFailure) {
      const message = typeof this.expectFailure === 'object' ?
        this.expectFailure.label :
        this.expectFailure;
      directive = this.reporter.getXFail(message);
    }

    if (this.reportedType) {
      details.type = this.reportedType;
    }
    if (!this.passed) {
      details.error = this.error;
    }
    if (this.attempt !== undefined) {
      details.attempt = this.attempt;
    }
    if (this.passedAttempt !== undefined) {
      details.passed_on_attempt = this.passedAttempt;
    }

    return { __proto__: null, details, directive };
  }

  report() {
    countCompletedTest(this);
    if (this.outputSubtestCount > 0) {
      this.reporter.plan(this.subtests[0].nesting, this.loc, this.outputSubtestCount);
    } else {
      this.reportStarted();
    }
    const report = this.getReportDetails();

    if (this.passed) {

Review comment (bug):
nit:

```suggestion
      const message = this.expectFailure?.label || this.expectFailure;
```

Code after:
        this.root.waitingOn > this.root.subtests.length) {
      // At this point all of the tests have finished running. However, there
      // might be ref'ed handles keeping the event loop alive. This gives the
      // global after() hook a chance to clean them up. The user may also
      // want to force the test runner to exit despite ref'ed handles.
      this.root.run();
    }
  }

  duration() {
    // Duration is recorded in BigInt nanoseconds. Convert to milliseconds.
    return Number(this.endTime - this.startTime) / 1_000_000;
  }

  getReportDetails() {
    let directive;
    const details = { __proto__: null, duration_ms: this.duration() };

    if (this.skipped) {
      directive = this.reporter.getSkip(this.message);
    } else if (this.isTodo) {
      directive = this.reporter.getTodo(this.message);
    } else if (this.expectFailure) {
      const message = typeof this.expectFailure === 'object' ?
        this.expectFailure.label :
        this.expectFailure;
      directive = this.reporter.getXFail(message);
    }

    if (this.reportedType) {
      details.type = this.reportedType;
    }
    if (!this.passed) {
      details.error = this.error;
    }
    if (this.attempt !== undefined) {
      details.attempt = this.attempt;
    }
    if (this.passedAttempt !== undefined) {
      details.passed_on_attempt = this.passedAttempt;
    }

    return { __proto__: null, details, directive };
  }

  report() {
    countCompletedTest(this);
    if (this.outputSubtestCount > 0) {
      this.reporter.plan(this.subtests[0].nesting, this.loc, this.outputSubtestCount);
    } else {
      this.reportStarted();