<h3 dir="auto">System info</h3>
<ul dir="auto">
<li>Playwright Version: 1.32.2</li>
<li>Operating System: Windows</li>
<li>Browser: Firefox</li>
</ul>
<h3 dir="auto">Source code</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I provided exact source code that allows reproducing the issue locally.</li>
</ul>




<p dir="auto"><strong>Link to the GitHub repository with the repro</strong></p>
<p dir="auto">[https://github.com/Smrtnyk/fetch-start-pw-repro]</p>
<p dir="auto"><strong>Steps</strong></p>
<ul dir="auto">
<li>Clone the repo</li>
<li>Run npm test</li>
</ul>
<p dir="auto"><strong>Expected</strong></p>
<p dir="auto">Test should not fail.</p>
<p dir="auto"><strong>Actual</strong></p>
<p dir="auto">After update to 1.32.2 from 1.25.2 this test started failing all the time.<br>
<code class="notranslate">fetchStart</code> from resource timings is always negative.<br>
If you revert to playwright version 1.25.2 it succeeds.<br>
Happens only on firefox in playwright, webkit and chromium are fine.<br>
Doesn't happen on real firefox.</p>
<h3 dir="auto">System info</h3>
<ul dir="auto">
<li>Playwright Version: v1.33.0</li>
<li>Operating System: Windows 11</li>
<li>Browser: WebKit</li>
<li>Other info:</li>
</ul>
<h3 dir="auto">Source code</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I provided exact source code that allows reproducing the issue locally.</li>
</ul>




<p dir="auto"><strong>Link to the GitHub repository with the repro</strong></p>
<p dir="auto"><a href="https://github.com/murolem/playwright-console-duplicates-on-webkit-issue">https://github.com/murolem/playwright-console-duplicates-on-webkit-issue</a></p>
<p dir="auto"><strong>Steps</strong></p>
<ul dir="auto">
<li>Run <code class="notranslate">npm run test:webkit</code> command to run test on WebKit with the issue.</li>
<li>Run <code class="notranslate">npm run test:chromium</code> or <code class="notranslate">npm run test:firefox</code> command to run test on Chromium or Firefox, respectively, which will pass successfully.</li>
</ul>
<p dir="auto"><strong>Expected</strong></p>
<p dir="auto">Test succeeds.</p>
<p dir="auto"><strong>Actual</strong></p>
<p dir="auto">Test will fail because instead of 2 messages being printed by the tested function, it will be 8 messages.</p>
<p dir="auto">These are the contents of tested function:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// index.ts

export function sayHello() {
    debugLog('saying hello...');
    debugLog('foo');
    debugLog('bar');
    debugLog('foo');
    console.log('hello world!');

    debugLog('and saying hello again...');
    debugLog('faz');
    debugLog('faz');
    console.log('hello world, again!');
}"><pre class="notranslate"><span class="pl-c">// index.ts</span>

<span class="pl-k">export</span> <span class="pl-k">function</span> <span class="pl-en">sayHello</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-en">debugLog</span><span class="pl-kos">(</span><span class="pl-s">'saying hello...'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-en">debugLog</span><span class="pl-kos">(</span><span class="pl-s">'foo'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-en">debugLog</span><span class="pl-kos">(</span><span class="pl-s">'bar'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-en">debugLog</span><span class="pl-kos">(</span><span class="pl-s">'foo'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'hello world!'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

    <span class="pl-en">debugLog</span><span class="pl-kos">(</span><span class="pl-s">'and saying hello again...'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-en">debugLog</span><span class="pl-kos">(</span><span class="pl-s">'faz'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-en">debugLog</span><span class="pl-kos">(</span><span class="pl-s">'faz'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'hello world, again!'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">v<br>
These are 2 functions that actually print something to console.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// index.ts

...
console.log('hello world!');
console.log('hello world, again!');
..."><pre class="notranslate"><span class="pl-c">// index.ts</span>

...
<span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'hello world!'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'hello world, again!'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
...</pre></div>
<p dir="auto">Below are the contents of the test.</p>
<p dir="auto">In test, console events are being listened for 1 second, then checks are made:</p>
<ol dir="auto">
<li>there should be only 2 console events</li>
<li>their content equals to what is being logged in the tested function.</li>
</ol>
<p dir="auto"><code class="notranslate">debugLog</code> function, which is being called from the tested function, does nothing except for checking that some random property exists on <code class="notranslate">window</code> object.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// index.test.ts

import { test, expect, ConsoleMessage } from '@playwright/test';
import { sayHello } from '../src/index.ts';

test('prints a &quot;hello world&quot; console message', async ({ page }) =&gt; {
    // expose a function `debugLog` which does nothing by itself
    // check if some random property on `window` object exists
    await page.exposeFunction('debugLog', (str: string) =&gt; {
        // @ts-ignore
        if(window['somePropertyThatDoesNotExists']) {
            // do something here...
        }
    });

    // define array of future console message and a listener which will be adding them here
    const consoleMessages: string[] = [];
    const consoleEventListener = (consoleMsg: ConsoleMessage) =&gt; {
        consoleMessages.push(consoleMsg.text());
    }
    page.addListener('console', consoleEventListener);

    // run `sayHello()`
    await page.evaluate((scriptStr) =&gt; {
        eval(scriptStr);

        sayHello();
    }, sayHello.toString());

    // waiting 1000ms for all messages to be printed
    await wait(1000);

    page.removeListener('console', consoleEventListener);
    
    // log collected messages
    console.log('console messages:', JSON.stringify(consoleMessages, null, 2));

    expect(consoleMessages.length).toBe(2);
    expect(consoleMessages[0]).toBe('hello world!');
    expect(consoleMessages[1]).toBe('hello world, again!');
});

async function wait(ms: number): Promise&lt;void&gt; {
    await new Promise(resolve =&gt; setTimeout(resolve, ms));
}"><pre class="notranslate"><span class="pl-c">// index.test.ts</span>

<span class="pl-k">import</span> <span class="pl-kos">{</span> <span class="pl-s1">test</span><span class="pl-kos">,</span> <span class="pl-s1">expect</span><span class="pl-kos">,</span> <span class="pl-smi">ConsoleMessage</span> <span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'@playwright/test'</span><span class="pl-kos">;</span>
<span class="pl-k">import</span> <span class="pl-kos">{</span> <span class="pl-s1">sayHello</span> <span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'../src/index.ts'</span><span class="pl-kos">;</span>

<span class="pl-en">test</span><span class="pl-kos">(</span><span class="pl-s">'prints a "hello world" console message'</span><span class="pl-kos">,</span> <span class="pl-k">async</span> <span class="pl-kos">(</span><span class="pl-kos">{</span> page <span class="pl-kos">}</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-c">// expose a function `debugLog` which does nothing by itself</span>
    <span class="pl-c">// check if some random property on `window` object exists</span>
    <span class="pl-k">await</span> <span class="pl-s1">page</span><span class="pl-kos">.</span><span class="pl-en">exposeFunction</span><span class="pl-kos">(</span><span class="pl-s">'debugLog'</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-s1">str</span>: <span class="pl-smi">string</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
        <span class="pl-c">// <span class="pl-k">@ts</span>-ignore</span>
        <span class="pl-k">if</span><span class="pl-kos">(</span><span class="pl-smi">window</span><span class="pl-kos">[</span><span class="pl-s">'somePropertyThatDoesNotExists'</span><span class="pl-kos">]</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
            <span class="pl-c">// do something here...</span>
        <span class="pl-kos">}</span>
    <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

    <span class="pl-c">// define array of future console message and a listener which will be adding them here</span>
    <span class="pl-k">const</span> <span class="pl-s1">consoleMessages</span>: <span class="pl-smi">string</span><span class="pl-kos">[</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-kos">[</span><span class="pl-kos">]</span><span class="pl-kos">;</span>
    <span class="pl-k">const</span> <span class="pl-en">consoleEventListener</span> <span class="pl-c1">=</span> <span class="pl-kos">(</span><span class="pl-s1">consoleMsg</span>: <span class="pl-smi">ConsoleMessage</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
        <span class="pl-s1">consoleMessages</span><span class="pl-kos">.</span><span class="pl-en">push</span><span class="pl-kos">(</span><span class="pl-s1">consoleMsg</span><span class="pl-kos">.</span><span class="pl-en">text</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
    <span class="pl-s1">page</span><span class="pl-kos">.</span><span class="pl-en">addListener</span><span class="pl-kos">(</span><span class="pl-s">'console'</span><span class="pl-kos">,</span> <span class="pl-s1">consoleEventListener</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

    <span class="pl-c">// run `sayHello()`</span>
    <span class="pl-k">await</span> <span class="pl-s1">page</span><span class="pl-kos">.</span><span class="pl-en">evaluate</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-s1">scriptStr</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
        <span class="pl-en">eval</span><span class="pl-kos">(</span><span class="pl-s1">scriptStr</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

        <span class="pl-en">sayHello</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span> <span class="pl-s1">sayHello</span><span class="pl-kos">.</span><span class="pl-en">toString</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

    <span class="pl-c">// waiting 1000ms for all messages to be printed</span>
    <span class="pl-k">await</span> <span class="pl-en">wait</span><span class="pl-kos">(</span><span class="pl-c1">1000</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

    <span class="pl-s1">page</span><span class="pl-kos">.</span><span class="pl-en">removeListener</span><span class="pl-kos">(</span><span class="pl-s">'console'</span><span class="pl-kos">,</span> <span class="pl-s1">consoleEventListener</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    
    <span class="pl-c">// log collected messages</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'console messages:'</span><span class="pl-kos">,</span> <span class="pl-smi">JSON</span><span class="pl-kos">.</span><span class="pl-en">stringify</span><span class="pl-kos">(</span><span class="pl-s1">consoleMessages</span><span class="pl-kos">,</span> <span class="pl-c1">null</span><span class="pl-kos">,</span> <span class="pl-c1">2</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

    <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-s1">consoleMessages</span><span class="pl-kos">.</span><span class="pl-c1">length</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toBe</span><span class="pl-kos">(</span><span class="pl-c1">2</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-s1">consoleMessages</span><span class="pl-kos">[</span><span class="pl-c1">0</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toBe</span><span class="pl-kos">(</span><span class="pl-s">'hello world!'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-s1">consoleMessages</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toBe</span><span class="pl-kos">(</span><span class="pl-s">'hello world, again!'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-k">async</span> <span class="pl-k">function</span> <span class="pl-en">wait</span><span class="pl-kos">(</span><span class="pl-s1">ms</span>: <span class="pl-smi">number</span><span class="pl-kos">)</span>: <span class="pl-smi">Promise</span><span class="pl-kos">&lt;</span><span class="pl-smi"><span class="pl-k">void</span></span><span class="pl-kos">&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-k">await</span> <span class="pl-k">new</span> <span class="pl-smi">Promise</span><span class="pl-kos">(</span><span class="pl-s1">resolve</span> <span class="pl-c1">=&gt;</span> <span class="pl-en">setTimeout</span><span class="pl-kos">(</span><span class="pl-s1">resolve</span><span class="pl-kos">,</span> <span class="pl-s1">ms</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">v</p>
<p dir="auto">Test output:</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&gt; playwright-console-duplicates-on-webkit-issue@1.0.0 test:webkit
&gt; npm run test -- --project=webkit


&gt; playwright-console-duplicates-on-webkit-issue@1.0.0 test
&gt; playwright test --project=webkit


Running 1 test using 1 worker
[webkit] › index.test.ts:4:1 › prints a &quot;hello world&quot; console message
console messages: [
  &quot;hello world!&quot;,
  &quot;hello world, again!&quot;,
  &quot;hello world, again!&quot;,
  &quot;hello world, again!&quot;,
  &quot;hello world, again!&quot;,
  &quot;hello world, again!&quot;,
  &quot;hello world, again!&quot;,
  &quot;hello world, again!&quot;
]
  1) [webkit] › index.test.ts:4:1 › prints a &quot;hello world&quot; console message ─────────────────────────

    Error: expect(received).toBe(expected) // Object.is equality

    Expected: 2
    Received: 8

      34 |     console.log('console messages:', JSON.stringify(consoleMessages, null, 2));
      35 |
    &gt; 36 |     expect(consoleMessages.length).toBe(2);
         |                                    ^
      37 |     expect(consoleMessages[0]).toBe('hello world!');
      38 |     expect(consoleMessages[1]).toBe('hello world, again!');
      39 | });

        at C:\Users\aliser\Desktop\repos\playwright-console-duplicates-on-webkit-issue\tests\index.test.ts:36:36

  1 failed
    [webkit] › index.test.ts:4:1 › prints a &quot;hello world&quot; console message ──────────────────────────"><pre class="notranslate"><span class="pl-k">&gt;</span> playwright-console-duplicates-on-webkit-issue@1.0.0 test:webkit
<span class="pl-k">&gt;</span> npm run <span class="pl-c1">test</span> -- --project=webkit


<span class="pl-k">&gt;</span> playwright-console-duplicates-on-webkit-issue@1.0.0 <span class="pl-c1">test</span>
<span class="pl-k">&gt;</span> playwright <span class="pl-c1">test</span> --project=webkit


Running 1 <span class="pl-c1">test</span> using 1 worker
[webkit] › index.test.ts:4:1 › prints a <span class="pl-s"><span class="pl-pds">"</span>hello world<span class="pl-pds">"</span></span> console message
console messages: [
  <span class="pl-s"><span class="pl-pds">"</span>hello world!<span class="pl-pds">"</span></span>,
  <span class="pl-s"><span class="pl-pds">"</span>hello world, again!<span class="pl-pds">"</span></span>,
  <span class="pl-s"><span class="pl-pds">"</span>hello world, again!<span class="pl-pds">"</span></span>,
  <span class="pl-s"><span class="pl-pds">"</span>hello world, again!<span class="pl-pds">"</span></span>,
  <span class="pl-s"><span class="pl-pds">"</span>hello world, again!<span class="pl-pds">"</span></span>,
  <span class="pl-s"><span class="pl-pds">"</span>hello world, again!<span class="pl-pds">"</span></span>,
  <span class="pl-s"><span class="pl-pds">"</span>hello world, again!<span class="pl-pds">"</span></span>,
  <span class="pl-s"><span class="pl-pds">"</span>hello world, again!<span class="pl-pds">"</span></span>
]
  1) [webkit] › index.test.ts:4:1 › prints a <span class="pl-s"><span class="pl-pds">"</span>hello world<span class="pl-pds">"</span></span> console message ─────────────────────────

    Error: expect(received).toBe(expected) // Object.is equality

    Expected: 2
    Received: 8

      34 <span class="pl-k">|</span>     console.log(<span class="pl-s"><span class="pl-pds">'</span>console messages:<span class="pl-pds">'</span></span>, JSON.stringify(consoleMessages, null, 2))<span class="pl-k">;</span>
      35 <span class="pl-k">|</span>
    <span class="pl-k">&gt;</span> 36 <span class="pl-k">|</span>     expect(consoleMessages.length).toBe(2)<span class="pl-k">;</span>
         <span class="pl-k">|</span>                                    ^
      37 <span class="pl-k">|</span>     expect(consoleMessages[0]).toBe(<span class="pl-s"><span class="pl-pds">'</span>hello world!<span class="pl-pds">'</span></span>)<span class="pl-k">;</span>
      38 <span class="pl-k">|</span>     expect(consoleMessages[1]).toBe(<span class="pl-s"><span class="pl-pds">'</span>hello world, again!<span class="pl-pds">'</span></span>)<span class="pl-k">;</span>
      39 <span class="pl-k">|</span> })<span class="pl-k">;</span>

        at C:<span class="pl-cce">\U</span>sers<span class="pl-cce">\a</span>liser<span class="pl-cce">\D</span>esktop<span class="pl-cce">\r</span>epos<span class="pl-cce">\p</span>laywright-console-duplicates-on-webkit-issue<span class="pl-cce">\t</span>ests<span class="pl-cce">\i</span>ndex.test.ts:36:36

  1 failed
    [webkit] › index.test.ts:4:1 › prints a <span class="pl-s"><span class="pl-pds">"</span>hello world<span class="pl-pds">"</span></span> console message ──────────────────────────</pre></div>