Skip to content

[Feature]: Add endTime to TestResult #39686

Closed as not planned
Closed as not planned

Description

@cpAdm

🚀 Feature Request

Add endTime property to TestResult which would be the end time of this particular test run.

(and probably add it to TestStep as well)

Example

No response

Motivation

Currently testResult.startTime + testResult.duration is smaller than the actual end time. So computing the end time from these two properties is not accurate.

In our use case, we need a more accurate timestamp because we match server logs to a specific test based on time.

Test showing this behaviour

test('should approximate end time from with startTime + duration', async ({ runInlineTest }) => {
  const result = await runInlineTest({
    'reporter.ts': `
      class Reporter {
        onTestEnd(test, result) {
          console.log('%%start=' + result.startTime.getTime());
          console.log('%%duration=' + result.duration);
        }
        onStdOut(data) {
          // forward test stdout so %%actualEndTest lines reach outputLines
          process.stdout.write(data.toString());
        }
      }
      module.exports = Reporter;
    `,
    'playwright.config.ts': `module.exports = { reporter: './reporter' };`,
    'a.spec.ts': `
      import { test } from '@playwright/test';
      test('timing', async () => {
        await new Promise(f => setTimeout(f, 250));
        console.log('%%actualEndTest=' + Date.now());
      });
    `,
  }, { reporter: '', workers: 1 });

  const start = Number(result.outputLines.find(l => l.startsWith('start='))!.split('=')[1]);
  const duration = Number(result.outputLines.find(l => l.startsWith('duration='))!.split('=')[1]);
  const actualEndTest = Number(result.outputLines.find(l => l.startsWith('actualEndTest='))!.split('=')[1]);

  const reportedTestEnd = start + duration;
  const delta = actualEndTest - reportedTestEnd;
  const dateToTime = (ms: number) => new Date(ms).toISOString().slice(11, 23); // HH:MM:SS.mmm
  console.log([
    `start\t\t${dateToTime(start)}`,
    `reportedEnd\t${dateToTime(reportedTestEnd)}`,
    `actualEnd\t${dateToTime(actualEndTest)}`,
    `durationMs\t${duration} ms`,
    `deltaMs\t\t${delta} ms`,
  ].join('\n'));
});

Relative: #38604

Activity

  1. pavelfeldman commented on Mar 15, 2026

    @pavelfeldman
    Member

    Currently testResult.startTime + testResult.duration is smaller than the actual end time. So computing the end time from these two properties is not accurate.

    what will endTime include that start + duration does not cover?

  2. cpAdm commented on Mar 17, 2026

    @cpAdm
    ContributorAuthor

    what will endTime include that start + duration does not cover?

    Well maybe it is actually a bug with duration (I have not yet looked deep in the playwright code), but testResult.startTime + testResult.duration should definetely be equal or large than actualEndTest in above example.

  3. dgozman commented on Mar 24, 2026

    @dgozman
    Collaborator

    Chris (@cpAdm) duration does not include things like beforeAll hooks or worker-scoped fixtures. Unfortunately, there is no good solution here - we want to both keep duration only include test-specific timings, but that does not necessary aligns with calling Date.now() in various places of the test.

  4. cpAdm commented on Mar 25, 2026

    @cpAdm
    ContributorAuthor

    Dmitry Gozman (@dgozman) Tricky. Maybe lets keep duration as is (for backwards compatibility), but add endTime which more closely reflects the actual end time?

  5. dgozman commented on Mar 25, 2026

    @dgozman
    Collaborator

    Chris (@cpAdm) Well, that would raise questions of why startTime + duration !== endTime 😄

    For your usecase, could you consider everything between two consecutive startTime values as belonging to the first test?

  6. cpAdm commented on Mar 25, 2026

    @cpAdm
    ContributorAuthor

    Dmitry Gozman (@dgozman) Fair point, although one could document why this is the case.

    It's a bit more tricky, since all tests run in parallel (so matching the logs isn't one-to-one to begin with). But I guess we could use parallelIndex to find the right next test for the current worker.

    (Currently we don't shard tests so missing shardIndex #38962, is not an issue.)

  7. areebmohammed commented on May 5, 2026

    @areebmohammed

    I've been looking at this and I think the right fix is at the IPC layer rather than trying to derive the end time from duration.
    Currently TestBeginPayload transmits startWallTime but TestEndPayload has no corresponding endWallTime, so the worker knows exactly when a test ended but throws that timestamp away. Since duration intentionally excludes beforeAll hooks and worker-scoped fixture teardown, no amount of math on the reporter side can recover the true wall-clock end time.
    The fix would be to add endWallTime to TestEndPayload in ipc.ts, populate it in the worker at the moment the end message is sent, propagate it through the dispatcher into a new endTime field on TestResult, and expose it in the public reporter API and HTML report.
    I'd like to implement this if the team is open to it

  8. vitalets commented on May 6, 2026

    @vitalets
    Contributor

    I was also struggling to calculate the exact timings for testBody start/end. With some math it's possible on the current data, but it's rather complex. Having these timings in the reporter API would be very helpful.

  9. Az8th commented on Jun 29, 2026

    @Az8th
    Contributor

    I agree that this would be appreciated, I could make use of an accurate endTime to include logs given by different traces tools when a test fails, only matching the correct time spawn and user

  10. pavelfeldman commented on Oct 31, 2026

    @pavelfeldman
    Member

    We're closing all P3-collecting-feedback issues and retiring the label. #43813 explains why. This doesn't mean the request is wrong. If it still matters to you, please open a new issue against the latest Playwright version with your concrete use case and link back here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions