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]: window.frameElement always evaluating to null #12844

Closed
3 tasks done
KuznetsovRoman opened this issue May 8, 2024 · 17 comments
Closed
3 tasks done

[🐛 Bug]: window.frameElement always evaluating to null #12844

KuznetsovRoman opened this issue May 8, 2024 · 17 comments
Labels
Bug 🐛 help wanted Issues that are free to take by anyone interested

Comments

@KuznetsovRoman
Copy link
Contributor

KuznetsovRoman commented May 8, 2024

Have you read the Contributing Guidelines on issues?

WebdriverIO Version

8.20.0

Node.js Version

18.12.1

Mode

Standalone Mode

Which capabilities are you using?

{
    browserName: 'chrome',
}

What happened?

I haven't found any way to get current frame with webdriverio methods, so iam trying to use browser.execute(globalThis.frameElement) to get currentFrame (to switch back after switchToFrame), but it always resolves null, though it works in browser console.

image

What is your expected behavior?

I expect to get an element reference, just like with findElement or when i execute document.documentElement.

How to reproduce the bug.

const { remote: wdioRemote } = require("webdriverio");

const session = await wdioRemote({
    automationProtocol: "devtools",
    port: 9515,
    hostname: "localhost",
    capabilities: {
        browserName: 'chrome',
    },
});

await session.url("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe");
const myIframe = await session.findElement('css selector', 'iframe') // getting iframe
await session.switchToFrame(myIframe) // switching frame
const childFrameElement = await session.execute('return globalThis.frameElement') // should not be null

if (!childFrameElement) {
    throw new Error("!");
}

Relevant log output

2024-05-08T17:24:04.207Z INFO webdriver: Initiate new session using the WebDriver protocol
2024-05-08T17:24:04.209Z INFO @wdio/utils: Connecting to existing driver at http://localhost:9515/
2024-05-08T17:24:04.309Z INFO webdriver: [POST] http://localhost:9515/session
2024-05-08T17:24:04.309Z INFO webdriver: DATA {
  capabilities: { alwaysMatch: { browserName: 'chrome' }, firstMatch: [ {} ] },
  desiredCapabilities: { browserName: 'chrome' }
}
2024-05-08T17:24:49.705Z INFO webdriver: COMMAND navigateTo("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
2024-05-08T17:24:49.708Z INFO webdriver: [POST] http://localhost:9515/session/b18445dea159a24092163d9bc01a068b/url
2024-05-08T17:24:49.709Z INFO webdriver: DATA {
  url: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe'
}
2024-05-08T17:24:50.646Z INFO webdriver: RESULT null
2024-05-08T17:25:08.906Z INFO webdriver: COMMAND findElement("css selector", "iframe")
2024-05-08T17:25:08.909Z INFO webdriver: [POST] http://localhost:9515/session/b18445dea159a24092163d9bc01a068b/element
2024-05-08T17:25:08.909Z INFO webdriver: DATA { using: 'css selector', value: 'iframe' }
2024-05-08T17:25:08.930Z INFO webdriver: RESULT {
  'element-6066-11e4-a52e-4f735466cecf': 'f.D168CFBC1393EFE0669A244839D21102.d.670998FA875B7743AECFB1A959C23003.e.6'
}
2024-05-08T17:25:17.147Z INFO webdriver: COMMAND switchToFrame(<object>)
2024-05-08T17:25:17.149Z INFO webdriver: [POST] http://localhost:9515/session/b18445dea159a24092163d9bc01a068b/frame
2024-05-08T17:25:17.150Z INFO webdriver: DATA {
  id: {
    'element-6066-11e4-a52e-4f735466cecf': 'f.D168CFBC1393EFE0669A244839D21102.d.670998FA875B7743AECFB1A959C23003.e.6'
  }
}
2024-05-08T17:26:07.844Z INFO webdriver: COMMAND executeScript("globalThis.frameElement", <object>)
2024-05-08T17:26:07.846Z INFO webdriver: [POST] http://localhost:9515/session/b18445dea159a24092163d9bc01a068b/execute/sync
2024-05-08T17:26:07.846Z INFO webdriver: DATA { script: 'globalThis.frameElement', args: [] }
2024-05-08T17:26:07.862Z INFO webdriver: RESULT null

Code of Conduct

  • I agree to follow this project's Code of Conduct

Is there an existing issue for this?

  • I have searched the existing issues
@KuznetsovRoman KuznetsovRoman added Bug 🐛 Needs Triaging ⏳ No one has looked into the issue yet labels May 8, 2024
@BorisOsipov
Copy link
Member

@KuznetsovRoman is it only for automationProtocol: "devtools", right?

@BorisOsipov BorisOsipov added help wanted Issues that are free to take by anyone interested and removed Needs Triaging ⏳ No one has looked into the issue yet labels May 8, 2024
@wdio-bot
Copy link
Contributor

wdio-bot commented May 8, 2024

Thanks for reporting!

We greatly appreciate any contributions that help resolve the bug. While we understand that active contributors have their own priorities, we kindly request your assistance if you rely on this bug being fixed. We encourage you to take a look at our contribution guidelines or join our friendly Discord development server, where you can ask any questions you may have. Thank you for your support, and cheers!

@KuznetsovRoman
Copy link
Contributor Author

KuznetsovRoman commented May 8, 2024

@KuznetsovRoman is it only for automationProtocol: "devtools", right?

No, when i change it to "webdriver", nothing changes

@christian-bromann
Copy link
Member

@KuznetsovRoman can you share WebdriverIO logs when running with WebDriver?

@KuznetsovRoman
Copy link
Contributor Author

KuznetsovRoman commented May 8, 2024

@KuznetsovRoman can you share WebdriverIO logs when running with WebDriver?

2024-05-08T17:24:04.207Z INFO webdriver: Initiate new session using the WebDriver protocol
2024-05-08T17:24:04.209Z INFO @wdio/utils: Connecting to existing driver at http://localhost:9515/
2024-05-08T17:24:04.309Z INFO webdriver: [POST] http://localhost:9515/session
2024-05-08T17:24:04.309Z INFO webdriver: DATA {
  capabilities: { alwaysMatch: { browserName: 'chrome' }, firstMatch: [ {} ] },
  desiredCapabilities: { browserName: 'chrome' }
}
2024-05-08T17:24:49.705Z INFO webdriver: COMMAND navigateTo("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
2024-05-08T17:24:49.708Z INFO webdriver: [POST] http://localhost:9515/session/b18445dea159a24092163d9bc01a068b/url
2024-05-08T17:24:49.709Z INFO webdriver: DATA {
  url: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe'
}
2024-05-08T17:24:50.646Z INFO webdriver: RESULT null
2024-05-08T17:25:08.906Z INFO webdriver: COMMAND findElement("css selector", "iframe")
2024-05-08T17:25:08.909Z INFO webdriver: [POST] http://localhost:9515/session/b18445dea159a24092163d9bc01a068b/element
2024-05-08T17:25:08.909Z INFO webdriver: DATA { using: 'css selector', value: 'iframe' }
2024-05-08T17:25:08.930Z INFO webdriver: RESULT {
  'element-6066-11e4-a52e-4f735466cecf': 'f.D168CFBC1393EFE0669A244839D21102.d.670998FA875B7743AECFB1A959C23003.e.6'
}
2024-05-08T17:25:17.147Z INFO webdriver: COMMAND switchToFrame(<object>)
2024-05-08T17:25:17.149Z INFO webdriver: [POST] http://localhost:9515/session/b18445dea159a24092163d9bc01a068b/frame
2024-05-08T17:25:17.150Z INFO webdriver: DATA {
  id: {
    'element-6066-11e4-a52e-4f735466cecf': 'f.D168CFBC1393EFE0669A244839D21102.d.670998FA875B7743AECFB1A959C23003.e.6'
  }
}
2024-05-08T17:26:07.844Z INFO webdriver: COMMAND executeScript("globalThis.frameElement", <object>)
2024-05-08T17:26:07.846Z INFO webdriver: [POST] http://localhost:9515/session/b18445dea159a24092163d9bc01a068b/execute/sync
2024-05-08T17:26:07.846Z INFO webdriver: DATA { script: 'return globalThis.frameElement', args: [] }
2024-05-08T17:26:07.862Z INFO webdriver: RESULT null

And looks like with webdriver protocol i can't get

@KuznetsovRoman
Copy link
Contributor Author

KuznetsovRoman commented May 8, 2024

UPD: INVALID. Don't need to be looked at. Also with "webdriver" protocol i can't get "documentElement" or any other element with "browser.execute":

Having the script:

await session.url("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe");

const divElement1 = await session.findElement('css selector', 'div') // getting div with findElement
const divElement2 = await session.execute('document.querySelector("div")') // getting div with execute

console.log({ divElement1, divElement2 });

I get this output with devtools protocol:

devtools logs

2024-05-08T17:37:46.927Z INFO webdriverio: Starting session using Chrome DevTools as automation protocol and Puppeteer as driver
2024-05-08T17:37:46.930Z INFO devtools:puppeteer: Initiate new session using the DevTools protocol
2024-05-08T17:37:46.932Z INFO devtools: Launch Google Chrome (undefined) with flags: --enable-automation --disable-popup-blocking --disable-extensions --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-sync --metrics-recording-only --disable-default-apps --mute-audio --no-first-run --no-default-browser-check --disable-hang-monitor --disable-prompt-on-repost --disable-client-side-phishing-detection --password-store=basic --use-mock-keychain --disable-component-extensions-with-background-pages --disable-breakpad --disable-dev-shm-usage --disable-ipc-flooding-protection --disable-renderer-backgrounding --force-fieldtrials=*BackgroundTracing/default/ --enable-features=NetworkService,NetworkServiceInProcess --disable-features=site-per-process,TranslateUI,BlinkGenPropertyTrees --window-position=0,0 --window-size=1200,900
2024-05-08T17:37:50.531Z INFO devtools: Connect Puppeteer with browser on port 59126
(node:63134) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
2024-05-08T17:37:51.313Z INFO devtools: COMMAND navigateTo("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
2024-05-08T17:38:02.414Z INFO devtools: RESULT null
2024-05-08T17:38:08.258Z INFO devtools: COMMAND findElement("css selector", "div")
2024-05-08T17:38:14.291Z INFO devtools: RESULT { 'element-6066-11e4-a52e-4f735466cecf': 'ELEMENT-1' }
2024-05-08T17:38:14.335Z INFO devtools: COMMAND executeScript("document.querySelector("div")", <object>)
2024-05-08T17:38:15.192Z INFO devtools: RESULT { 'element-6066-11e4-a52e-4f735466cecf': 'ELEMENT-2' }
{
  divElement1: { 'element-6066-11e4-a52e-4f735466cecf': 'ELEMENT-1' },
  divElement2: { 'element-6066-11e4-a52e-4f735466cecf': 'ELEMENT-2' }
}

So divElement1 and divElement2 are both defined.

And here is the output with webdriver protocol:

webdriver logs

2024-05-08T17:35:43.992Z INFO webdriver: Initiate new session using the WebDriver protocol
2024-05-08T17:35:43.993Z INFO @wdio/utils: Connecting to existing driver at http://localhost:9515/
2024-05-08T17:35:44.077Z INFO webdriver: [POST] http://localhost:9515/session
2024-05-08T17:35:44.078Z INFO webdriver: DATA {
  capabilities: { alwaysMatch: { browserName: 'chrome' }, firstMatch: [ {} ] },
  desiredCapabilities: { browserName: 'chrome' }
}
2024-05-08T17:35:44.856Z INFO webdriver: COMMAND navigateTo("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
2024-05-08T17:35:44.860Z INFO webdriver: [POST] http://localhost:9515/session/1828e08e471868f7f2bb66ef3f6de4aa/url
2024-05-08T17:35:44.860Z INFO webdriver: DATA {
  url: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe'
}
2024-05-08T17:36:42.691Z INFO webdriver: RESULT null
2024-05-08T17:36:42.692Z INFO webdriver: COMMAND findElement("css selector", "div")
2024-05-08T17:36:42.694Z INFO webdriver: [POST] http://localhost:9515/session/1828e08e471868f7f2bb66ef3f6de4aa/element
2024-05-08T17:36:42.694Z INFO webdriver: DATA { using: 'css selector', value: 'div' }
2024-05-08T17:36:42.710Z INFO webdriver: RESULT {
  'element-6066-11e4-a52e-4f735466cecf': 'f.93616B8FD091DE6963D77FB3C7D38FB0.d.167C1079BDAABAA0A4570639B68C6F7E.e.19'
}
2024-05-08T17:36:42.712Z INFO webdriver: COMMAND executeScript("document.querySelector("div")", <object>)
2024-05-08T17:36:42.713Z INFO webdriver: [POST] http://localhost:9515/session/1828e08e471868f7f2bb66ef3f6de4aa/execute/sync
2024-05-08T17:36:42.713Z INFO webdriver: DATA { script: 'document.querySelector("div")', args: [] }
2024-05-08T17:36:42.727Z INFO webdriver: RESULT null
{
  divElement1: {
    'element-6066-11e4-a52e-4f735466cecf': 'f.93616B8FD091DE6963D77FB3C7D38FB0.d.167C1079BDAABAA0A4570639B68C6F7E.e.19'
  },
  divElement2: null
}

divElement2 is now undefined

@BorisOsipov
Copy link
Member

@KuznetsovRoman
const divElement2 = await session.execute('document.querySelector("div")') => const divElement2 = await session.execute('return document.querySelector("div")')

missing return statement here and seems in all cases. Please check.

@KuznetsovRoman
Copy link
Contributor Author

missing return statement here and seems in all cases. Please check.

Oh. It is not needed in devtools, but IS needed in webdriver. That works, thanks.

Not with await session.execute('return globalThis.frameElement') though. Still returns null after switchToFrame

@christian-bromann
Copy link
Member

Not with await session.execute('return globalThis.frameElement') though. Still returns null after switchToFrame

This is because this object can't be serialized. Note the in WebDriver all objects you return need to be serializeable. Mind trying to return a specific string or boolean property?

@KuznetsovRoman
Copy link
Contributor Author

This is because this object can't be serialized. Note the in WebDriver all objects you return need to be serializeable. Mind trying to return a specific string or boolean property?

But i can use await session.execute('return document.querySelector("div")') for example. It evaluates:

{ "element-6066-11e4-a52e-4f735466cecf": "f.B8857766B2104CC0DBB1D43DEB0F3C3A.d.F61D61186B7F43EDA24E8DEAE54EA227.e.8" }

And it is a valid webdriver element. So why can't i get similar result with await session.execute('return globalThis.frameElement')?

@christian-bromann
Copy link
Member

It seems like accessing frameElement is actually returning null, see

Screenshot 2024-05-08 at 1 34 48 PM

Note: see that I selected the iframe as execution context.

@KuznetsovRoman
Copy link
Contributor Author

KuznetsovRoman commented May 8, 2024

It seems like accessing frameElement is actually returning null, see

Yeah, looks like frameElement works weirdly overall, and wdio is not the cause here.

Actually, i don't need exactly globalThis.frameElement, i just want to get current frame (to check if browser.switchToFrame was previously called and return back to that frame)

globalThis.frameElement was just my attempt to get some workaround

@christian-bromann
Copy link
Member

Yeah, looks like frameElement works weirdly overall, and wdio is not the cause here.

I was not using WebdriverIO for this screenshot, this is just my default browser console. Can you verify you can actually access this property, since it can be null based on security settings.

@KuznetsovRoman
Copy link
Contributor Author

I was not using WebdriverIO for this screenshot, this is just my default browser console. Can you verify you can actually access this property, since it can be null based on security settings.

I can't access the property. I found an iframe example where frameElement in devtools console returns html-element, and i always get an error:

2024-05-12T20:33:07.637Z INFO webdriver: COMMAND executeScript("return frameElement", <object>)
2024-05-12T20:33:07.639Z INFO webdriver: [POST] http://localhost:9515/session/185b3370efe6a7cddef78d590a0f6d90/execute/sync
2024-05-12T20:33:07.639Z INFO webdriver: DATA { script: 'return frameElement', args: [] }
2024-05-12T20:33:07.667Z WARN webdriver: Request failed with status 500 due to javascript error: {"status":10,"value":"stale element not found in the current frame"}
  (Session info: chrome=124.0.6367.158)
2024-05-12T20:33:07.669Z INFO webdriver: Retrying 1/3
2024-05-12T20:33:07.669Z INFO webdriver: [POST] http://localhost:9515/session/185b3370efe6a7cddef78d590a0f6d90/execute/sync
2024-05-12T20:33:07.670Z INFO webdriver: DATA { script: 'return frameElement', args: [] }
2024-05-12T20:33:07.689Z WARN webdriver: Request failed with status 500 due to javascript error: {"status":10,"value":"stale element not found in the current frame"}
  (Session info: chrome=124.0.6367.158)
2024-05-12T20:33:07.689Z INFO webdriver: Retrying 2/3
2024-05-12T20:33:07.690Z INFO webdriver: [POST] http://localhost:9515/session/185b3370efe6a7cddef78d590a0f6d90/execute/sync
2024-05-12T20:33:07.690Z INFO webdriver: DATA { script: 'return frameElement', args: [] }
2024-05-12T20:33:07.704Z WARN webdriver: Request failed with status 500 due to javascript error: {"status":10,"value":"stale element not found in the current frame"}
  (Session info: chrome=124.0.6367.158)
2024-05-12T20:33:07.706Z INFO webdriver: Retrying 3/3
2024-05-12T20:33:07.706Z INFO webdriver: [POST] http://localhost:9515/session/185b3370efe6a7cddef78d590a0f6d90/execute/sync
2024-05-12T20:33:07.706Z INFO webdriver: DATA { script: 'return frameElement', args: [] }
2024-05-12T20:33:07.719Z ERROR webdriver: Request failed with status 500 due to javascript error: javascript error: {"status":10,"value":"stale element not found in the current frame"}
  (Session info: chrome=124.0.6367.158)
Uncaught:
javascript error: javascript error: {"status":10,"value":"stale element not found in the current frame"}
  (Session info: chrome=124.0.6367.158)
    at getErrorFromResponseBody (file:///Users/kroman512/clean/wdio-headless/node_modules/webdriver/build/utils.js:194:12)
    at NodeJSRequest._request (file:///Users/kroman512/clean/wdio-headless/node_modules/webdriver/build/request/index.js:164:23)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Browser.wrapCommandFn (file:///Users/kroman512/clean/wdio-headless/node_modules/@wdio/utils/build/shim.js:81:29)
    at async Browser.wrapCommandFn (file:///Users/kroman512/clean/wdio-headless/node_modules/@wdio/utils/build/shim.js:81:29)
    at async REPL68:1:33

That is webdriver protocol. With devtools, it executes normally, but returns an empty object ({})

What is the intended way to get currentFrame with webdriver then? How to check if i am inside of some frame?

@christian-bromann
Copy link
Member

I found an iframe example where frameElement in devtools console returns html-element, and i always get an error:

Can you provide a reproducible example?

@KuznetsovRoman
Copy link
Contributor Author

Can you provide a reproducible example?

This one should work:

import { remote as wdioRemote } from "webdriverio";

const session = await wdioRemote({
    automationProtocol: "webdriver",
    port: 9515,
    hostname: "localhost",
    capabilities: {
        browserName: 'chrome',
    },
})

await session.url("https://www.youtube.com/");
const myIframe = await session.findElement('css selector', 'iframe') // getting iframe
await session.switchToFrame(myIframe) // switching frame
const childFrameElement = await session.execute('return globalThis.frameElement') // should not be null

console.log({childFrameElement})

It throws "stale element not found in the current frame" at "session.execute"

@christian-bromann
Copy link
Member

Thank you. I can confirm that it would expect that returning the frameElement should result in the return of a WebDriver reference for the execute command. I can't tell why it returns null. I recommend to raise an issue to the WebDriver specification to raise awareness.

I possible workaround would be something like this:

import { remote as wdioRemote } from './packages/webdriverio/build/index.js'

const session = await wdioRemote({
    capabilities: {
        browserName: 'chrome',
    },
})

await session.url('https://www.youtube.com/')
const myIframe = await session.findElement('css selector', 'iframe') // getting iframe
await session.switchToFrame(myIframe) // switching frame

const frameId = Date.now().toString()
await session.execute((frameId) => {
    globalThis.frameElement?.setAttribute('data-frame-id', frameId)
}, frameId)

await session.switchToParentFrame()
console.log(await session.$(`iframe[data-frame-id="${frameId}"]`))

I will go ahead and close this as I don't see how WebdriverIO can help mitigate this issue since it is rather a protocol issue. Let me know if you have further problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug 🐛 help wanted Issues that are free to take by anyone interested
Projects
None yet
Development

No branches or pull requests

4 participants