Parse Element ID within iframe using Webview in VB.net - vb.net

I have a webpage that loads caller data when a caller calls. I am trying to parse the element ids but they are loaded in an iframe. How would i go about doint this?
The iframe is and the elements are on default.html <iframe onload="UserFrameLoaded();" name="cmUserFrame" id="view_cmUserFrame" style="display: block; overflow: scroll;" marginheight="0" width="100%" height="1415px" frameborder="0" marginwidth="0" src="./CallManager_files/default.html"></iframe>
the code im using is
Dim firstNameText As String = Await WebView21.ExecuteScriptAsync("document.getElementById('m.first_name').textContent")
i tried
Dim firstNameText As String = Await WebView21.ExecuteScriptAsync("document.getElementById('view_cmUserFrame').contentWindow.document.getElementById('m.first_name').textContent")
Im not sure if the iframes source is on another domain. Im hoping not...
I can probably just save the webpage locally and then load default.html directly but i am not sure how to save the webpage with webview either.

You pretty much are asking a Javascript question, however, things might be easier for you if you understand a little more about Webview2 and how you can access those frames.
First option is FrameCreated Event which will fire when the cmUserFrame is created in the top document. From this you get a frame and you can then use ExecuteScriptAsync from that frame object.
Next up you have AddScriptToExecuteOnDocumentCreatedAsync with this it will inject your script into each document that is created. In this case you could have Javascript that checks the name of the document/Frame and then if it is the right frame continues with your javascript.
With respect to you actual Javascript, without knowing the actual page it is difficult to know. open the Dev tools of either Chrome or edge and then the console and copy past your javascript into there to see if it works there first. If it works there then you have a timing issue. If it does not work then you need to work on what is not being found.
Updated From Comments
To help you understand the Webview2 frame events here is an Issue from Github
One more link from Webview2 GitHub issues.
Specifically to answer your questions.
Implement FrameCreated
Wait for the frame with the name you want
Wait for DomContentCompleted event
Call ExecuteScriptAsync ONE THE FRAME you get from 2
Code would then be assuming that that frame's document is as you have in your js
Dim firstNameText As String = Await WebView21FRAME.ExecuteScriptAsync("document.getElementById('m.first_name').textContent")

Related

NightwatchJS: Safari can't find nested iFrame

I'm having difficulty testing a piece of code using NightwatchJS with Selenium and SafariDriver.
I have an open issue for this on nightwatch repo, although am not sure if it is an issue with nightwatch or something deeper.
The HTML content to be tested looks something like:
<body>
<iframe id="top-iframe" src="about:blank">
#document
<html>
<body>
<container>
<!-- access this iframe to test -->
<iframe id="nested-iframe" src="news.google.com"></iframe>
</container>
</body>
</html>
</iframe>
</body>
Where #nested-frame will need to be accessed from the top level document for inspection of content.
The test code is using NightwatchJS, more details about config, setup and code are in the GitHub issue.
The Gist of the issue:
The problem is that to access the nested iFrame, it needs to first find #top-frame web element, use the returned web element and pass it to frame which makes the WebDriver call to change context of test session to that frame. This is all good with Chrome, FF, and Safari as they can all find this frame web element and make the switch into the frame context. My test that Safari was changing iFrame context, although not sure how good it is, was to try and find another DOM element other than the nested frame, which it could find. The problem comes when with Safari, after switching into #top-frame, it cannot find the #nested-frame web element, and Nightwatch returns a 404 no such element from the HTTP call. Strange, right?
It is very puzzling, my latest thinking was maybe it was a cross origin issue. But then I read on WebDriver switch to frame:
NOTE WebDriver is not bound by the same origin policy, so it is always possible to switch into child browsing contexts, even if they are different origin to the current browsing context.
And I also tried checking Disable Cross Origin Restrictions from Safari Developer menu.
As mentioned before, I can find another DOM element in the #top-frame. I tried things like 10-15s timeouts thinking maybe it needed to load. I can inspect the browser with debugger and see that #nested-frame is there and the content loads as expected. There are not console errors indicating any content failed to load.
It's very puzzling to me and I'm not sure how to further debug. Maybe someone else with a fresh perspective could have a suggestion or if someone has run into a similar situation as this. Throwing this out into the universe as information is limited on the topic too, so maybe this could help someone else. TIA!
iframes
As per the documentation iframe is a construct which embeds a document into an HTML document so that embedded data is displayed inside a subwindow of the browser's window. This does not mean full inclusion and the two documents are independent, and both them are treated as complete documents, instead of treating one as part of the other.
iframe structure and details
Generally, an iframe element is in the form of:
<iframe src="URL" more attributes>
alternative content for browsers which do not
support iframe
</iframe>
Browsers which support iframe display the document referred to by the URL in a subwindow, typically with vertical and/or horizontal scroll bars. Such browsers ignore the content of the iframe element (i.e. everything between the start tag <iframe...> and the end tag </iframe>). Browsers which do not support iframe (or have such support disabled) does the opposite, i.e. process the content as if the <iframe...> and </iframe> tags were not there. Thus, the content matters, despite being ignored by some browsers.
This usecase
As the top-level <iframe> is having src="about:blank" it is highly unlikely there can be any child <iframe>. Hence, in absence of any child <iframe> your attempt to access any nested <iframe> will fail.
Reference
You can find a relevant detailed discussion in:
Ways to deal with #document under iframe
After discussion with Selenium team, this appears to be a bug with Apple.
I have filed a ticket with Apple here.

Unable to switch to iframe in Selenium chromedriver when iframe is directly under body tag [duplicate]

For the portal I am testing now, I came with the problem that I could not create any xpath locators, after some time I figured out that it was because of an '#document', this cuts the path and makes the simple "copy xpath" to direct the path to a completely different element.
<iframe id="FRAMENAME" src="/webclient/workspace/launch-task/REMbl?ds=BP" width="100%" height="100%" frameborder="0" data-navitemname="navitemname" style="" xpath="1">
#document
<html>
CODE....
</html>
I found the solution for this is it is simply add a switchTo like this:
driver.switchTo().frame("FRAMENAME");
This works and makes the rest of the code to work properly but, takes some extra time processing this command till the code moves to the next line.
So I would like to ask, is there is a better solution for this? something smarter/faster?
I am concerned that when the point where I have lots of scripts comes, the execution time will take too long.
I don't use id locators for example because they are all dynamic so sometimes a xpath is required.
Thank you!
To work with elements inside iframe you must switch to this specific iframe.
Your solution .switchTo().frame("FRAMENAME"); is correct. Selenium does not have any other ways to work with iframe wrappers.
inline frames
As per the documentation in Using inline frames, an inline frame is a construct which embeds a document into an HTML document so that embedded data is displayed inside a subwindow of the browser's window. This does not mean full inclusion and the two documents are independent, and both them are treated as complete documents, instead of treating one as part of the other.
iframe structure and details
Generally, an iframe element is in the form of:
<iframe src="URL" more attributes>
alternative content for browsers which do not
support iframe
</iframe>
Browsers which support iframe display the document referred to by the URL in a subwindow, typically with vertical and/or horizontal scroll bars. Such browsers ignore the content of the iframe element (i.e. everything between the start tag <iframe...> and the end tag </iframe>). Browsers which do not support iframe (or have such support disabled) does the opposite, i.e. process the content as if the <iframe...> and </iframe> tags were not there. Thus, the content matters, despite being ignored by some browsers.
So to summarize, inline frames do not mean an include feature, although it might sometimes serve similar purposes.
Note that, when inline frames are used, the browser (if it supports them) sends a request to the server referred to by the URL in the iframe element, and after getting the requested document displays it inside an inline frame. In this sense inline frames are a joint browser-server issue, but only the browser needs to be specifically iframe-aware; from the server's point of view, there's just a normal HTTP request for a document, and it sends the document without having (or needing) any idea on what the browser is going to do with it.
Something Smarter
As per the best practices while switching to an iframe you need to induce WebDriverWait as follows:
Switch through Frame Name (Java Sample Code):
new WebDriverWait(driver, 20).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.name("frame_name")));
Switch through iframe XPath (Python Sample Code):
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[#id='ptifrmtgtframe' and #name='TargetContent']")))
Switch through iframe CssSelector (C# Sample Code):
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe#twitter-widget-0")));
Reference
You can find a couple of relevant discussions in:
Python: How can I select a html element no matter what frame it is in in selenium?
Java: Is it possible to switch to an element in a frame without using driver.switchTo().frame(“frameName”) in Selenium Webdriver Java?
C#: How to wait for a frame to load before locating an element?
tl; dr
Inline frames vs. normal frames

access waveform.png inside .css sheet to use webkit-mask?

based on the custom-player-examples im building my own player.
i used the minimal-player template.
after i set up the player like i want it to be, i started to customize the design (color.css, structure.css, standard,css)
but now i am stuck badly..
i found out that i cant change the background-color of the waveforms unless i use a webkit or the waveform.js.
the webkit should do just fine for me...
my only problem is,
i dont know how to acess the track.waveform_url in neither my index.html or *.css files.
i know its inside waveform-container div but i need the url
.wavekit{
-webkit-mask-box-image: url(**IN HERE!!!**);
background: #81D8D0;
height: 280px;
width: 100%;
bottom: 0px;
position: fixed;
}
inside my stylesheet..
sadly i cant provide a link because its only on my hard drive yet
can somebody please help me out here?
thank you verymuch
Well, this is very hacky, but after a couple of attempts I haven't found a better way to get waveform URL.
Idea is that for first play there is an event of 'ajaxSuccess' that is firing and for the next ones there is 'scPlayer:onAudioReady' event. The point being that image’s DOM is being generated by the plugin only at some point, so we need a certain “hook” like an event to know for sure the image will be already present in DOM.
$(document).bind('ajaxSuccess scPlayer:onAudioReady', function () {
// get image from DOM of player
// it will be re-set every next play
console.log($('.sc-waveform-container > img').attr('src'));
$('.wavekit').style({
'-webkit-mask-box-image': $('.sc-waveform-container > img').attr('src')
});
});
Here's working example http://jsbin.com/uhofom/2/edit (only tested in Chrome)
Custom player project is outdated and will probably not get much attention. Its current state is not very extendable from the JavaScript point of view.
My suggestion would be to use something like Audio5JS or SoundManager2 to play music and to have custom HTML and CSS UI. To get actual sounds or sets data you could query our HTTP API or use SoundCloud JavaScript SDK. Then you'd have proper object with all data including waveform API and would control the process much better.

Facebook Application Link and JS SDK

Hello guys I have two small questions about my facebook application link and JS SDK. So let me explain:
1- Well as I understood from Facebook JS SDK, the should be left just empty. But still I am a little dizzy and I want to make sure whether we should put our page content into it or it should be left empty?
Please make me sure about it.
2- I have put some changes in my css and markup of my page but after one day I can not see some of the changes in my facebook application link.
How can I see the result of changes if there is such a way??
Thank you very much indeed.
Let me answer this for you:
1) Yes, It should be left empty and here's the info on why it's required quoted from JS SDK docs:
The JavaScript SDK requires the fb-root element in order to load properly and a call to
FB.init to initialize the SDK with your app ID correctly.
The fb-root element must not be hidden using display: none or
visibility: hidden, or some parts of the SDK will not work properly in
Internet Explorer.
The SDK inserts elements into fb-root which expect to be positioned
relative to the body or relative to an element close to the top of the
page. It is best if the fb-root element is not inside of an element
with position: absolute or position: relative. If you must place the
fb-root element inside of a positioned element, then you should also
give it a position close to the top of the body or some parts of the
SDK may not work properly.
2) It's most probably a cache problem, there's a similar question with an issue of css which has been answered previously: Caching for css content for iphone FB APP
Also to get your browser/visitors browser to re-fetch your CSS file, The trick is to pass a query param/variable at the end of the CSS file url like so: ?v=1
<link rel="stylesheet" href="css/style.css?v=1">
This will automatically make your browser or maybe even facebook to fetch your CSS file again with the new changes. Make sure to change the number everytime you update your files so you could see the changes instantly.

How to edit html (tags), before being executed by CppWebBrowser

I can't solve my problem, and I hope somebody knows how...
I have a component on my form TCppWebBrowser, and when I navigate to a URL, after the document was downloaded, in method OnDocumentComplete() , I'm trying to check and change html source of loaded document... before it being executed by browser.
I need that, because some websites have background sounds, and I want to parse html and remove tags or just remove text which contains sound files like *.wav , *.mid , *.swf, *.mp3 ... ect.
For example if html source have this line:
<NOEMBED><BGSOUND src="/images/ImagineCut.wav"></NOEMBED>
then, i change it to:
<NOEMBED><BGSOUND src="/images/ImagineCut."></NOEMBED>
or I can delete whole tag.
Using this way I want to mute webbrowser or even to stop playing sounds. Please take into consideration this method, because it will help me to avoid all kind of sounds after I edited html.. (before browser execute it)
That's what I tried to do:
void __fastcall TForm1::CppWebBrowser1DocumentComplete(TObject *Sender,
LPDISPATCH pDisp, Variant *URL)
{
IHTMLDocument2 *pHTMLDoc;
CppWebBrowser1->Document->QueryInterface(IID_IHTMLDocument2,(LPVOID*)&pHTMLDoc);
IHTMLElement *pElem;
pHTMLDoc->get_body(&pElem);
BSTR text;
pElem->get_innerHTML(&text);
text = Cleaning(text); //checking and changing html without souds
pElem->put_innerHTML(text);
pElem->Release();
pHTMLDoc->Release();
}
To do what you are asking, you would have to download the HTML file yourself from outside of the TCppWebBrowser component completely, alter the HTML as needed, and then push the new HTML into TCppWebBrowser using one of its IPersist... interfaces. Examples of doing that have been posted in the Borland/CodeGear/Embarcadero forums many times before.