<p dir="auto">Hi all - I've run in to a problem that has stumped me for the past day. I think I've narrowed down the scenario and need some help figuring out if I'm on the right track here. (Video and code reproductions below to replicate passing and failing scenarios)</p>
<p dir="auto">I'm using <code class="notranslate">@tanstack/react-table</code> to render a table in my NextJS application. There is an action button above the table that will display a <code class="notranslate">div</code> when this button is clicked. I'd like to run a playwright test to click on the action button and confirm that the div is displayed, however, when I do, my test time's out with an error of:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="locator.click: Target closed
=========================== logs ===========================
waiting for getByTestId('create-address-button')
  locator resolved to &lt;button class=&quot;ml-auto hidden h-8 lg:flex&quot; data-testid=&quot;…&gt;Create Address&lt;/button&gt;
attempting click action
  waiting for element to be visible, enabled and stable
  element is visible, enabled and stable
  scrolling into view if needed
  done scrolling
  performing click action
============================================================"><pre class="notranslate"><code class="notranslate">locator.click: Target closed
=========================== logs ===========================
waiting for getByTestId('create-address-button')
  locator resolved to &lt;button class="ml-auto hidden h-8 lg:flex" data-testid="…&gt;Create Address&lt;/button&gt;
attempting click action
  waiting for element to be visible, enabled and stable
  element is visible, enabled and stable
  scrolling into view if needed
  done scrolling
  performing click action
============================================================
</code></pre></div>
<p dir="auto">The crazy thing is that if I comment out the <code class="notranslate">@tanstack/react-table</code> code, the playwright test successfully targets the action button and my test passes.</p>
<p dir="auto">My hypothesis is that playwright is attempting to click on the button while the table is rendering/re-rendering/initializing causing the <code class="notranslate">useState</code> <code class="notranslate">setter</code> I'm using in the <code class="notranslate">onClick</code> to go "stale"? I don't want to have to worry about the render state of the table since these actions are different and it's not like I have to wait for the table to finish to click on the button above.</p>
<p dir="auto">If I remove the <code class="notranslate">setShowDiv</code> from the <code class="notranslate">onClick</code>, the playwright test successfully runs up until the check to see if the <code class="notranslate">div</code> exists (since now we removed the line of code that should set it's visibility) I can also get around this by adding a hard-coded timeout but don't want to do that either.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// index.tsx

const [showDiv, setShowDiv] = useState(false);
...
...
&lt;AddressDataTableToolbar
    // comment out this line
    table={table}
    onClick={(show) =&gt; {
        setShowDiv(show); // &lt;-- this goes stale possibly?
    }}
/&gt;"><pre class="notranslate"><code class="notranslate">// index.tsx

const [showDiv, setShowDiv] = useState(false);
...
...
&lt;AddressDataTableToolbar
    // comment out this line
    table={table}
    onClick={(show) =&gt; {
        setShowDiv(show); // &lt;-- this goes stale possibly?
    }}
/&gt;
</code></pre></div>
<p dir="auto">Is there something fundamental I'm missing or is this a scenario that Playwright should be able to handle?</p>
<h3 dir="auto">System info</h3>
<ul dir="auto">
<li>Playwright Version: 1.34.3</li>
<li>Operating System: macOS</li>
<li>Browser: WebKit</li>
<li>Other info:</li>
</ul>
<h3 dir="auto">Source code</h3>
<ul dir="auto">
<li>[x ] I provided exact source code that allows reproducing the issue locally.</li>
</ul>
<p dir="auto">Local reproduction</p>
<p dir="auto"><strong>Steps</strong></p>
<ul dir="auto">
<li>Pull code from <a href="https://github.com/uncvrd/tanstack-playwright">https://github.com/uncvrd/tanstack-playwright</a></li>
<li>run <code class="notranslate">npm install</code></li>
<li>run <code class="notranslate">npm run dev</code></li>
<li>In a separate terminal, run <code class="notranslate">npx playwright test --ui</code></li>
<li>run test called <code class="notranslate">should click on the table header</code></li>
<li>observe output failure</li>
<li>view <code class="notranslate">index.tsx</code> remove references to <code class="notranslate">@tanstack/react-table</code> code (i left comments on the lines to remove, lines: 23, 28, 30, 84)</li>
<li>run test called <code class="notranslate">should click on the table header</code></li>
<li>observe successful test</li>
</ul>
<p dir="auto">I just want to click the button and not have to wait for the table to render because these two functionalities are separate</p>
<p dir="auto">Here's a video showing the initial failed state (the first 0:25 seconds are just waiting for it to fail)</p>
<details open="" class="details-reset border rounded-2">
  <summary class="px-3 py-2">
    <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-camera-video">
    <path d="M16 3.75v8.5a.75.75 0 0 1-1.136.643L11 10.575v.675A1.75 1.75 0 0 1 9.25 13h-7.5A1.75 1.75 0 0 1 0 11.25v-6.5C0 3.784.784 3 1.75 3h7.5c.966 0 1.75.784 1.75 1.75v.675l3.864-2.318A.75.75 0 0 1 16 3.75Zm-6.5 1a.25.25 0 0 0-.25-.25h-7.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-6.5ZM11 8.825l3.5 2.1v-5.85l-3.5 2.1Z"></path>
</svg>
    <span aria-label="Video description Screen.Recording.2023-05-27.at.4.18.08.PM.mov" class="m-1">Screen.Recording.2023-05-27.at.4.18.08.PM.mov</span>
    <span class="dropdown-caret"></span>
  </summary>

  <video src="https://user-images.githubusercontent.com/25097099/241449117-c2618e35-5c98-4f39-b22e-0be68a82f032.mov" data-canonical-src="https://user-images.githubusercontent.com/25097099/241449117-c2618e35-5c98-4f39-b22e-0be68a82f032.mov" controls="controls" muted="muted" class="d-block rounded-bottom-2 border-top width-fit" style="max-height:640px; min-height: 200px">

  </video>
</details>

<p dir="auto">Here's a video showing me removing the table code and running the test to successful completion where the button is clicked and the div is displayed.</p>
<details open="" class="details-reset border rounded-2">
  <summary class="px-3 py-2">
    <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-camera-video">
    <path d="M16 3.75v8.5a.75.75 0 0 1-1.136.643L11 10.575v.675A1.75 1.75 0 0 1 9.25 13h-7.5A1.75 1.75 0 0 1 0 11.25v-6.5C0 3.784.784 3 1.75 3h7.5c.966 0 1.75.784 1.75 1.75v.675l3.864-2.318A.75.75 0 0 1 16 3.75Zm-6.5 1a.25.25 0 0 0-.25-.25h-7.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-6.5ZM11 8.825l3.5 2.1v-5.85l-3.5 2.1Z"></path>
</svg>
    <span aria-label="Video description Screen.Recording.2023-05-27.at.4.18.57.PM.mov" class="m-1">Screen.Recording.2023-05-27.at.4.18.57.PM.mov</span>
    <span class="dropdown-caret"></span>
  </summary>

  <video src="https://user-images.githubusercontent.com/25097099/241448921-e95c50e9-92d5-4bf4-849c-f9fbac488e7c.mov" data-canonical-src="https://user-images.githubusercontent.com/25097099/241448921-e95c50e9-92d5-4bf4-849c-f9fbac488e7c.mov" controls="controls" muted="muted" class="d-block rounded-bottom-2 border-top width-fit" style="max-height:640px; min-height: 200px">

  </video>
</details>

<p dir="auto">Hopefully I've identified the reason for the failing test, but please let me know if the title does not accurately represent the reason why this test fails</p>
<p dir="auto">[Describe expected behavior]</p>
<p dir="auto">I should not have to wait for the table to render to click on the button</p>
<p dir="auto">[Describe actual behavior]</p>
<p dir="auto">The test fails due to <code class="notranslate">locator.click: Target closed</code></p>
<p dir="auto">Thanks a lot for the help :)</p>
<h3 dir="auto">System info</h3>
<ul dir="auto">
<li>Playwright Version: 1.29.2</li>
<li>Operating System: MacOS Ventura</li>
<li>Browser: Chrome</li>
<li>NodeJS version: v16.16.0</li>
<li>Other info: Running the android server for Pixel 4 and Nexus 5X with Android 11. Issue exists on real device as well as emulator.</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>Server script</strong></p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="async function launchAndroidServer() {
  const browserServer = await _android.launchServer({
    port: 5555,
    wsPath: &quot;ws&quot;,
  });

  const wsEndpoint = browserServer.wsEndpoint();
  console.log(&quot;wsEndpoint:: &quot;, wsEndpoint);
}

launchAndroidServer();"><pre class="notranslate"><span class="pl-k">async</span> <span class="pl-k">function</span> <span class="pl-en">launchAndroidServer</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-s1">browserServer</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">_android</span><span class="pl-kos">.</span><span class="pl-en">launchServer</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
    <span class="pl-c1">port</span>: <span class="pl-c1">5555</span><span class="pl-kos">,</span>
    <span class="pl-c1">wsPath</span>: <span class="pl-s">"ws"</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">const</span> <span class="pl-s1">wsEndpoint</span> <span class="pl-c1">=</span> <span class="pl-s1">browserServer</span><span class="pl-kos">.</span><span class="pl-en">wsEndpoint</span><span class="pl-kos">(</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">"wsEndpoint:: "</span><span class="pl-kos">,</span> <span class="pl-s1">wsEndpoint</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-en">launchAndroidServer</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">Client Script</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="const { _android } = require('playwright');

(async () =&gt; {
  const device = await _android.connect(
      'ws://127.0.0.1:5555/ws'
  );

  console.log(`Model :: ${device.model()}, serial:: ${device.serial()}`)

  await device.shell('am force-stop com.android.chrome');
  const context = await device.launchBrowser();

  const page = await context.newPage();
  await page.goto('https://playwright.dev/');

  await page.close();
  await context.close();
})();
"><pre class="notranslate"><span class="pl-k">const</span> <span class="pl-kos">{</span> _android <span class="pl-kos">}</span> <span class="pl-c1">=</span> <span class="pl-en">require</span><span class="pl-kos">(</span><span class="pl-s">'playwright'</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-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-k">const</span> <span class="pl-s1">device</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">_android</span><span class="pl-kos">.</span><span class="pl-en">connect</span><span class="pl-kos">(</span>
      <span class="pl-s">'ws://127.0.0.1:5555/ws'</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">`Model :: <span class="pl-s1"><span class="pl-kos">${</span><span class="pl-s1">device</span><span class="pl-kos">.</span><span class="pl-en">model</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">}</span></span>, serial:: <span class="pl-s1"><span class="pl-kos">${</span><span class="pl-s1">device</span><span class="pl-kos">.</span><span class="pl-en">serial</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">}</span></span>`</span><span class="pl-kos">)</span>

  <span class="pl-k">await</span> <span class="pl-s1">device</span><span class="pl-kos">.</span><span class="pl-en">shell</span><span class="pl-kos">(</span><span class="pl-s">'am force-stop com.android.chrome'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">const</span> <span class="pl-s1">context</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">device</span><span class="pl-kos">.</span><span class="pl-en">launchBrowser</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-s1">page</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">context</span><span class="pl-kos">.</span><span class="pl-en">newPage</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">await</span> <span class="pl-s1">page</span><span class="pl-kos">.</span><span class="pl-en">goto</span><span class="pl-kos">(</span><span class="pl-s">'https://playwright.dev/'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

  <span class="pl-k">await</span> <span class="pl-s1">page</span><span class="pl-kos">.</span><span class="pl-en">close</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">await</span> <span class="pl-s1">context</span><span class="pl-kos">.</span><span class="pl-en">close</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-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto"><strong>Steps</strong></p>
<ul dir="auto">
<li>Run the server script</li>
<li>Run the client script</li>
</ul>
<p dir="auto"><strong>Expected</strong><br>
New browser page should be opened and test should get executed.</p>
<p dir="auto"><strong>Actual</strong><br>
The client script execution doesn't proceed after the <code class="notranslate">await context.newPage()</code> command. The new chrome browser page is opened with the URL as <code class="notranslate">about:blank</code> and the test does not proceed.</p>
<p dir="auto">Client and server logs added below:<br>
<a href="https://github.com/microsoft/playwright/files/10928374/pw_android_client.log">pw_android_client.log</a><br>
<a href="https://github.com/microsoft/playwright/files/10928375/pw_android_server.log">pw_android_server.log</a></p>