Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Unable to adopt element handle from a different document #2974

Closed
jperl opened this issue Jul 16, 2020 · 12 comments
Closed

[BUG] Unable to adopt element handle from a different document #2974

jperl opened this issue Jul 16, 2020 · 12 comments
Assignees

Comments

@jperl
Copy link
Contributor

jperl commented Jul 16, 2020

Context:

  • Playwright Version: 1.2.1
  • Operating System: Mac
  • Node version: v12.16.3
  • Browser: Chromium

Code Snippet

const { chromium } = require("playwright-chromium");

(async () => {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto("https://haircuttery.com");
  await page.click("#salonSearch-header");
  await page.fill("#salonSearch-header", "59718");
  await page.click("#submit");
  await page.click(
    '[href="/client/checkin.html?reqType=newappointment&salonid=4390"]'
  );

  // error here
  await page.waitForSelector("html");
})();

Describe the bug

We want to get the html element to scroll it. However we are unable to get the element since it fails with this error: await page.waitForSelector("html"); fails with "Unable to adopt element handle from a different document"

 pw:api   waiting for scheduled navigations to finish [] +0ms
  pw:api navigated to "https://haircuttery.com/client/checkin.html?reqType=newappointment&salonid=4390" [] +261ms
  pw:api   navigations have finished [] +3ms
  pw:api <= page.click succeeded +0ms
  pw:api => page.waitForSelector started +1ms
  pw:api waiting for selector "html" to be visible [] +0ms
  pw:api   selector resolved to visible <html lang="en">…</html> [] +48ms
  pw:api <= page.waitForSelector failed +312ms
(node:91208) UnhandledPromiseRejectionWarning: Error: Unable to adopt element handle from a different document
================ page.waitForSelector logs ================
[api] waiting for selector "html" to be visible
[api]   selector resolved to visible <html lang="en">…</html>
============================================================
Note: use DEBUG=pw:api environment variable and rerun to capture Playwright logs.
    at FrameSession._adoptBackendNodeId (/Users/jon/dev/examples/pw-core/node_modules/playwright-chromium/lib/chromium/crPage.js:745:19)
    at runMicrotasks (<anonymous>)
    at runNextTicks (internal/process/task_queues.js:62:5)
    at processImmediate (internal/timers.js:429:9)
    at async /Users/jon/dev/examples/pw-core/node_modules/playwright-chromium/lib/frames.js:394:33
    at async ProgressController.run (/Users/jon/dev/examples/pw-core/node_modules/playwright-chromium/lib/progress.js:77:28)
    at async /Users/jon/dev/examples/pw-core/haircuttery.js:13:3
  -- ASYNC --
    at Frame.waitForSelector (/Users/jon/dev/examples/pw-core/node_modules/playwright-chromium/lib/helper.js:78:23)
    at /Users/jon/dev/examples/pw-core/node_modules/playwright-chromium/lib/page.js:131:61
    at Page._attributeToPage (/Users/jon/dev/examples/pw-core/node_modules/playwright-chromium/lib/page.js:356:20)
    at Page.waitForSelector (/Users/jon/dev/examples/pw-core/node_modules/playwright-chromium/lib/page.js:131:21)
    at Page.waitForSelector (/Users/jon/dev/examples/pw-core/node_modules/playwright-chromium/lib/helper.js:79:31)
    at /Users/jon/dev/examples/pw-core/haircuttery.js:13:14
    at runNextTicks (internal/process/task_queues.js:62:5)
    at processImmediate (internal/timers.js:429:9)
(node:91208) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:91208) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
@aslushnikov
Copy link
Collaborator

@jperl doesn't repro for me on Mac. Is this behavior flaky? Does it still repro for you?

@jperl
Copy link
Contributor Author

jperl commented Jul 21, 2020

@aslushnikov Hmm that's odd, yes I just ran it and got the same error using [email protected] 5 out of 5 times.

@jperl
Copy link
Contributor Author

jperl commented Jul 21, 2020

Sorry it's a weird reproduction, just something I encountered using playwright on random sites. This is a slightly more robust selector that is not geographically dependent.

const { chromium } = require("playwright-chromium");

(async () => {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto("https://haircuttery.com");
  await page.click("#salonSearch-header");
  await page.fill("#salonSearch-header", "60007");
  await page.click("#submit");
  await page.click("text=Book Your Appointment Now");
  // instead of  await page.click('[href="/client/checkin.html?reqType=newappointment&salonid=4390"]');
  await page.waitForSelector("html");
  await browser.close();
})();

@DJ-Glock
Copy link

Got the same error in my tests one time, look flaky. :(

@DJ-Glock
Copy link

DJ-Glock commented Jul 23, 2020

@aslushnikov can you please provide some explanation about nature of this error?
Unable to adopt element handle from a different document

I have the following case:

  1. Open the website URL in tab 1. It will redirect us to login page.
  2. Login to the website.
  3. Open the same website URL in tab 2.
  4. Perform a logout from the website in tab 2. Ensure that logout performed successfully and login page was opened. Close tab 2.
  5. Wait for 4-5 seconds and check tab 1. It should be redirected to Login page (there is an iframe that checks session and logs user out).
  6. Reopen login page by opening website URL in tab 1. And here it fails from time to time with the following error:
Unable to adopt element handle from a different document
================ page.waitForSelector logs ================
[api] waiting for selector "body header" to be visible
[api]   selector resolved to visible <header class="MuiPaper-root MuiAppBar-root MuiAppBar-po…>…</header>
============================================================
Note: use DEBUG=pw:api environment variable and rerun to capture Playwright logs.
Error: Unable to adopt element handle from a different document
================ page.waitForSelector logs ================
[api] waiting for selector "body header" to be visible
[api]   selector resolved to visible <header class="MuiPaper-root MuiAppBar-root MuiAppBar-po…>…</header>
============================================================
Note: use DEBUG=pw:api environment variable and rerun to capture Playwright logs.
    at FrameSession._adoptBackendNodeId (node_modules/playwright-chromium/lib/chromium/crPage.js:745:19)
    at runMicrotasks (<anonymous>)
    at runNextTicks (internal/process/task_queues.js:62:5)
    at processImmediate (internal/timers.js:429:9)
    at /e2e/node_modules/playwright-chromium/lib/frames.js:394:33
    at ProgressController.run (node_modules/playwright-chromium/lib/progress.js:77:28)
    at LoginPage.open (src/Pages/Login/LoginPage.ts:52:5)
    at Context.<anonymous> (src/Tests/Login/Login.e2e.ts:68:7)

This happens from time to time in headless mode in Docker (ubuntu bionic image with pw 1.2.1) but never happened in headful mode on Windows. I have no idea how to reproduce it :(
Same test in puppeteer and older chromium works fine (didn't try new chromium).

Update:
It looks like I understood why it happens in my case.
On the 6th step, when I opening my website, before redirecting, just for about 0.5 second, website main page appears and then it's being redirected to the login page. So probably PW captures header element from the main page when it's being redirected.

@jperl
Copy link
Contributor Author

jperl commented Aug 24, 2020

I can no longer reproduce this, will add a reproduction if I encounter it again.

@dgozman
Copy link
Contributor

dgozman commented Nov 9, 2020

Closing because we don't have a repro.

@HelenMariia
Copy link

Hey! I have the same issue but with different details. I'll try to provide them:

Context:
Playwright Version: 1.10.0
Jest-playwright-preset: ~1.5.2
Operating System: Ubuntu
Node version: v12.13.0
Browser: Chromium

Code Snippet

it('Check user's products', async () => {
   ...
  // here where related logic starts: 
  await page.waitForSelector(selectors.linkTile);
  const tiles = await page.$$(selectors.linkTile);
  const productIds: string[] = [];

  for (const tile of tiles) {
    productIds.push(await readMetadata(tile));
  }
  expect(productIds.every((id) => user.availableProducts.includes(id))).toEqual(true);
  });

This code uses readMetadata helper. Here this mistakes comes:

export const readMetadata = async (element: ElementHandle<SVGElement | HTMLElement>): Promise<string> => {
return (await element.getAttribute(DATA_META_SELECTOR)) as string;
};

Describe the bug

 elementHandle.getAttribute: Unable to adopt element handle from a different document

      3 |
      4 | export const readMetadata = async (element: ElementHandle<SVGElement | HTMLElement>): Promise<string> => {
    > 5 |   return (await element.getAttribute(DATA_META_SELECTOR)) as string;
        |                         ^
      6 | };
      7 |
      at Object.captureStackTrace (../node_modules/playwright/lib/utils/stackTrace.js:48:19)
      at Connection.sendMessageToServer (../node_modules/playwright/lib/client/connection.js:69:48)
      at Proxy.<anonymous> (../node_modules/playwright/lib/client/channelOwner.js:64:61)
      at ../node_modules/playwright/lib/client/elementHandle.js:75:42
      at ElementHandle._wrapApiCall (../node_modules/playwright/lib/client/channelOwner.js:77:34)
      at ElementHandle.getAttribute (../node_modules/playwright/lib/client/elementHandle.js:74:21)
      at tests/helpers/metadata.ts:5:25
      at step (tests/helpers/metadata.ts:33:23)
      at Object.next (tests/helpers/metadata.ts:14:53)
      at tests/helpers/metadata.ts:8:71

or at the same place sometimes happens one more problem:

elementHandle.getAttribute: Protocol error (DOM.describeNode): Cannot find context with specified id

      3 |
      4 | export const readMetadata = async (element: ElementHandle<SVGElement | HTMLElement>): Promise<string> => {
    > 5 |   return (await element.getAttribute(DATA_META_SELECTOR)) as string;
        |                         ^
      6 | };
      7 |

      at Object.captureStackTrace (../node_modules/playwright/lib/utils/stackTrace.js:48:19)
      at Connection.sendMessageToServer (../node_modules/playwright/lib/client/connection.js:69:48)
      at Proxy.<anonymous> (../node_modules/playwright/lib/client/channelOwner.js:64:61)
      at ../node_modules/playwright/lib/client/elementHandle.js:75:42
      at ElementHandle._wrapApiCall (../node_modules/playwright/lib/client/channelOwner.js:77:34)
      at ElementHandle.getAttribute (../node_modules/playwright/lib/client/elementHandle.js:74:21)
      at tests/helpers/metadata.ts:5:25
      at step (tests/helpers/metadata.ts:33:23)
      at Object.next (tests/helpers/metadata.ts:14:53)
      at tests/helpers/metadata.ts:8:71

@dgozman
Copy link
Contributor

dgozman commented Jun 22, 2021

@HelenMariia Since you are using an ElementHandle that points to a particular element in the page, this error means that the element is not available anymore. Most likely, the page has navigated somewhere while you are trying to get the attribute value. I suspect there is a race where navigation usually happens before you call getAttribute, but sometimes after? Try using waitForSelector to ensure that the page is stable and some key elements are visible, and then call getAttribute.

@HelenMariia
Copy link

@dgozman Thanks for your advice! Actually, waitForSelector is added here. All related logic run on the same page without navigation. The only thing I found out now is that during loading process page reloads one more time. But it happens before await page.waitForSelector(selectors.linkTile); starts. So still can't find a way to improve the test. Looks like everything is logical.

@dgozman
Copy link
Contributor

dgozman commented Jun 22, 2021

@HelenMariia If you do page.getAttribute(selector, DATA_META_SELECTOR) instead of using ElementHandle, Playwright should be able to handle this situation for you - retry after that sudden page reload and get the attribute value. Could you try that?

When using the ElementHandle.getAttribute API, it implies that particular Element to be present on the page. That's not the case with page reload because everything is recreated from scratch after the reload, therefore it throws the error (the error message could be improved for sure!) and cannot do anything meaningful.

@HelenMariia
Copy link

Yeah, I tried write this way (also simplified the helper - move it directly to test) - and now all tests are passed!

for (const tile of tiles) {
    commodityIds.push((await page.getAttribute(HomePageSelectors.linkTile, DATA_META_SELECTOR)) as string);
  }

the only problem that remains is that when I refer to page.getAttribute I got the array with 5 same tiles. I tried to do with forEach() but it can't be used with async/await, so still looking for a way to kill it. But the answer is close! Thank you :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants