Repository: microsoft/playwright
File: packages/playwright/src/reporters/line.ts (TypeScript)

Code before:
      this.screen.stdout.write(this.screen.colors.yellow(header) + '\n');
      this.screen.stdout.write(this.screen.colors.yellow('    Paused at test end. Press Ctrl+C to end.') + '\n');
    }

    this.writeLine();
    this.writeLine();

    this._updateLine(test, result, undefined);

    await new Promise<void>(() => {});
  }

  override onTestEnd(test: TestCase, result: TestResult) {
    super.onTestEnd(test, result);

    const printedCount = this._printedErrorCounts.get(result);
    this._printedErrorCounts.delete(result);
    if (printedCount !== undefined) {
      const newErrors = result.errors.slice(printedCount);
      if (newErrors.length > 0) {
        if (!process.env.PW_TEST_DEBUG_REPORTERS) {
          this.screen.stdout.write(`\u001B[1A\u001B[2K`);
          this.screen.stdout.write(`\u001B[1A\u001B[2K`);
        }
        this.writeLine();
        for (const error of formatResultFailure(this.screen, test, { ...result, errors: newErrors }, '    '))
          this.writeLine(error.message + '\n');
        this.writeLine();
        this.writeLine();
      }
      return;
    }

    if (!this.willRetry(test) && (test.outcome() === 'flaky' || test.outcome() === 'unexpected' || result.status === 'interrupted')) {
      if (!process.env.PW_TEST_DEBUG_REPORTERS)
        this.screen.stdout.write(`\u001B[1A\u001B[2K`);
      this.writeLine(this.formatFailure(test, ++this._failures));
      this.writeLine();
    }
  }

  private _updateLine(test: TestCase, result: TestResult, step?: TestStep) {
    const retriesPrefix = this.totalTestCount < this._current ? ` (retries)` : ``;
    const prefix = `[${this._current}/${this.totalTestCount}]${retriesPrefix} `;
    const currentRetrySuffix = result.retry ? this.screen.colors.yellow(` (retry #${result.retry})`) : '';
    const title = this.formatTestTitle(test, step) + currentRetrySuffix;
    if (process.env.PW_TEST_DEBUG_REPORTERS)
      this.screen.stdout.write(`${prefix + title}\n`);
    else
      this.screen.stdout.write(`\u001B[1A\u001B[2K${prefix + this.fitToScreen(title, prefix)}\n`);
  }

Review comment (suggestion):
- I don't understand why `this.epilogue()` won't print all the errors anyway.
- (just an idea) we can mark errors with some symbol to avoid double-printing them.

Code after:
      if (!process.env.PW_TEST_DEBUG_REPORTERS)
        this.screen.stdout.write(`\u001B[1A\u001B[2K`);
      this.writeLine(this.formatFailure(test, ++this._failures));
      this.writeLine();
    }
  }

  private _updateLine(test: TestCase, result: TestResult, step?: TestStep) {
    const retriesPrefix = this.totalTestCount < this._current ? ` (retries)` : ``;
    const prefix = `[${this._current}/${this.totalTestCount}]${retriesPrefix} `;
    const currentRetrySuffix = result.retry ? this.screen.colors.yellow(` (retry #${result.retry})`) : '';
    const title = this.formatTestTitle(test, step) + currentRetrySuffix;
    if (process.env.PW_TEST_DEBUG_REPORTERS)
      this.screen.stdout.write(`${prefix + title}\n`);
    else
      this.screen.stdout.write(`\u001B[1A\u001B[2K${prefix + this.fitToScreen(title, prefix)}\n`);
  }

  override onError(error: TestError): void {
    super.onError(error);

    const message = this.formatError(error).message + '\n';
    if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin)
      this.screen.stdout.write(`\u001B[1A\u001B[2K`);
    this.screen.stdout.write(message);
    this.writeLine();
  }

  override async onEnd(result: FullResult) {
    if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin)
      this.screen.stdout.write(`\u001B[1A\u001B[2K`);
    await super.onEnd(result);
    this.epilogue(false);
  }
}

export default LineReporter;