I am evaluating this framework with my application and so far I am not able to use it for the reason mentioned below:
My application has UI framework consisting of frames. Also, lots of UI related common info like height, width, top level navigation links etc is part of top level frame. And this info is being reffered in child frames/pages as "top.variable" or "top.function"
etc.
If I use this LTA framework, my top level frame is replaced by a frame from this LTAF frame. Clearly, the info that my app is looking for is not a part of LTA Framework and hence it ends up with lots of script errors.
Changing my app would not be feasible because of the large scope of the changes, probably entire app.
Does anyone has any idea/comment on resolving this issue with minimal changes in LTA Framework itself?
If your website depends on frames referencing their parent, then most likely you want to navigate to the whole frameset, and then automate only one of the frames.
Automating frames in LTAF is a feature that will be included in our next release. However, the core functionality is already included in the April release, what's missing is a way to expose it by our API. The changes to enable it are very simple
1. Le's suppose that you have a "FrameSet.htm" that loads 2 separate pages into frames:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>This is the top page</title>
</head>
<body>
<span id="SpanInFrame">This is the top page</span>
<input type="button" id="ButtonInFrame" value="Button In Frame" onclick="document.getElementById('SpanInFrame').innerHTML='Button has been clicked';" />
</body>
</html>
2. Assuming that the majority of your application is loaded into the top frame, then you want LTAF to navigate to the frameset and then to target the top frame for all subsequent actions. To enable this, modify HtmlPage.cs as follows:
2.1 First we need a small flag to indicate if we have navigated to the frameset. You want to turn this on at the end of the current Navigate method.
2.2 Next, you modify the ExecuteCommand method to check if this flag is set, and modify the command to add the frame information:
public BrowserInfo ExecuteCommand(BrowserCommand command)
{
if (_firstNavigateComplete)
{
command.Target.FrameHierarchy = new string[1] { "topFrame" };
}
...
3. Now you can automate a test agains the topFrame regularly:
[WebTestMethod]
public void FrameTest()
{
HtmlPage page = new HtmlPage("FrameSet.htm");
HtmlElement span = page.Elements.Find("SpanInFrame");
Assert.AreEqual("This is the top page", span.GetInnerText());
page.Elements.Find("ButtonInFrame").Click();
Assert.AreEqual("Button has been clicked", span.GetInnerText());
}
That's it. You'll notice that in step 2.2 I hard coded "topFrame" in there, but you could very easily store the name of the frame in some variable that you initialize when constructing the HtmlPage.
Some closing comments:
- If you need it, I can send you a private with this fix.
- For next release, this functionality will be exposed by a public "GetFrame" method on HtmlPage, so that you could write:
HtmlPage framesetPage = new HtmlPage("frameset.htm");
HtmlPage topPage = framesetPage.GetFrame("topFrame");
Hope it helps, let me know if this is not what you meant by your original post.
For next release a lot of the methods in HtmlPage will be marked as virtual to make it simpler to extend. When that happens, one will be able to inherit from HtmlPage and override the ExecuteCommand method to modify the command just before it is sent to
the browser.
This is another way to accomplish the modification that I posted above.
Your suggestion surely helps in one of my scenarios but it doesnot address my main concern. Let me explain my situation with help of sample code below:
<HTML xmlns="http://www.w3.org/1999/xhtml">
<SCRIPT language=javascript type=text/javascript src="/JavaScript/Global.js"></SCRIPT>
<BODY>
<SCRIPT type=text/javascript>
//<![CDATA[
function _hdrRaisePopup()
{
if (typeof (top.PopupWindow) =='function') { //in LTAF, error occurs here
top.PopupWindow('/samplepage.aspx', 800, 600); //('top' refers to LTAF frame instead of main window where JS file is included)
}
else if (typeof (top.ShowPopupWindow) =='function') { //same here
top.ShowPopupWindow('/samplepage.aspx', 800, 600) //same here
}
else {
alert('Unable to raise popup window');
}
}
//]]>
</SCRIPT>
<div>
<IFRAME style="WIDTH: 240px; HEIGHT: 660px; TOP: 55px; LEFT: 0px" id="id1" src="/menupage.aspx" name="navMenuFrame" ></IFRAME>
<IFRAME style="WIDTH: 1352px; HEIGHT: 940px; TOP: 55px; LEFT: 244px" id="id2" src="/mainpage.aspx" name="mainFrame" ></IFRAME>
<IFRAME style="WIDTH: 1352px; HEIGHT: 0px; TOP: 995px; LEFT: 244px" id="id3" src="/detailpage.aspx" name="detailFrame" ></IFRAME>
</div>
<!-- Other HTML elements ... -->
</BODY></HTML>
On line 2, external JavaScript is referenced and appended in top-level window of the browser.
Now, when frames on line 23, 24, and 25 are navigated to respective pages, script error occurs same as mentioned on line 9, 10, 12 & 13.
So basically, in javascript code wherever is the reference of 'top' keyword, it will not work as 'top' refers to the LTAF frame instead of my app's main frame window.
Oh, I get it now. Yeah, this is a problem with LTAF right now.
One work around is to use the new popup window support to have your pages run in their own window instead of inside LTAF's frame. You can accomplish this by writting something like this in your test code:
[WebTestMethod]
public void AutomaticPopup()
{
// navigate to some page so that you can run scripts
HtmlPage p = new HtmlPage("SomeRandomPageInYourSite.htm");
// execute a script that opens a new window that loads your real site
p.ExecuteScript("function openWindow() { window.open('../TheRealPage.htm'); return true;} openWindow();");
// get the popupwindow and automate against it.
HtmlPage newPage = p.GetPopupWindow(1);
Assert.AreEqual("This is the page", newPage.Elements.Find("body", 0).GetInnerText());
}
Although I verified that this works, it is far from optimal because you don't want each test to open a new window. However, if this approach works for you, one thing that we could do is add a feature to LTAF where all your tests run on the new window. What
this would do is before start running any tests, it will automatically create a popup window by the technique that I showed here, and all your tests will run against that window instead (the test code will look the same).
Lately I needed to focus on some other stuff in our project so I couldn't proceed with your test code.
Now that I tried it and found that It still doesnot work as it is trying to execute the script in the testFrame context and eventually ends up with the following JS exception:
Error in Test 'UserManagementTests.SignInAndSignOut'
Exception was thrown by the client engine: "[TestExecutorException]: Unhandled JS exception while executing command handler function ExecuteScript. (Details: {\"name\":\"TypeError\",\"message\":\"Object
doesn't support this property or method\",\"number\":-2146827850,\"description\":\"Object doesn't support this property or method\"})" when running command: ExecuteScript on the target: < id=, index: 0>.
Exception Details:
Microsoft.Web.Testing.Light.WebTestException: Exception was thrown by the client engine: "[TestExecutorException]: Unhandled JS exception while executing command handler function ExecuteScript. (Details: {\"name\":\"TypeError\",\"message\":\"Object doesn't
support this property or method\",\"number\":-2146827850,\"description\":\"Object doesn't support this property or method\"})" when running command: ExecuteScript on the target: < id=, index: 0>.
Source Error:
Line 14:
Line 15: // execute a script that opens a new window that loads your real site
Line 16: page.ExecuteScript("function openWindow() { window.open('Login.aspx'); return true;} openWindow();");
Line 17:
Line 18: // get the popupwindow and automate against it.
[Microsoft.Web.Testing.Light.WebTestException: Exception was thrown by the client engine: "[TestExecutorException]: Unhandled JS exception while executing command handler function ExecuteScript. (Details: {\"name\":\"TypeError\",\"message\":\"Object doesn't support this property or method\",\"number\":-2146827850,\"description\":\"Object doesn't support this property or method\"})" when running command: ExecuteScript on the target: < id=, index: 0>.]
at Microsoft.Web.Testing.Light.HtmlPage.ExecuteCommand(BrowserCommand command) in C:\Users\mosborn.000\Desktop\Microsoft.Web.Testing.Lightweight\Framework\UI\HtmlPage.cs:line 110
at Microsoft.Web.Testing.Light.HtmlPage.ExecuteScript(String scriptExpression) in C:\Users\mosborn.000\Desktop\Microsoft.Web.Testing.Lightweight\Framework\UI\HtmlPage.cs:line 207
at UserManagementTests.SignInAndSignOut() in c:\v5\Www\UI\App_Code\Tests\UserManagementTests.cs:line 16
Version Information: Microsoft .NET Framework Version: 2.0.50727.3082; ASP.NET Version: 2.0.50727.4005; ASP.NET AJAX Version: 3.5.30729.196; Microsoft.Web.Testing Version: 1.0.0.0</div>
My web test method looks like as below:
[
WebTestMethod]
public
void SignInAndSignOut()
{
// Navigate to the login page
HtmlPage page =
new
HtmlPage("TrueBlank.aspx");
// execute a script that opens a new window that loads your real site
page.ExecuteScript("function openWindow() { window.open('Login.aspx'); return true;} openWindow();");
// get the popupwindow and automate against it.
HtmlPage newPage = page.GetPopupWindow(1);
// Fill Login control user/password and click login button
page.Elements.Find("UserName").SetText("UItestUser");
page.Elements.Find(
"Password").SetText("password");
page.Elements.Find("butLogin").Click(WaitFor.Postback);
// Verify content of the Home page
Assert.AreEqual("Application Home Page",
page.Elements.Find("slblApplicationHomePage").GetInnerText());
// Click the logout link
page.Elements.Find("shlLogout").Click(WaitFor.Postback);
// Verify login button now exists.
Assert.IsTrue(page.Elements.Exists("butLogin"));
}
I traced back to the LTAF code where it was failing:
evalInActiveFrame : function(expression) {
// Frame containing the running test (where the script must be evaluated)
var frame = TestExecutor.get_activeWindow().get_activeFrame().get_jsFrame();
// Safari doesn't support changing the context of the eval function,
// so it has to be done specially
if ("safari" != DomSupport.get_navigatorName())
{
return frame.eval(expression); //IT FAILS AT THIS LINE
}
.
.
.
}
Can you provide some other insight?
Besides this, yes, it would be of great help if we can run the tests in new windows. Also, currently, test running frames can be used to display outputs/exceptions/logs etc instead.
Unfortunately, I could not repro this problem on my side, so maybe I am doing something different. I am assuming your browser settings enable popup windows from script? Could you let me know what browser your are using?
I am interested in investigating this to see if there is a bug on our side, can you email me so that I can send you what I have to see if it works on your environment? Mail is farmas@microsoft.com
I just came across this issue. It appears that when page = *.aspx then ExecuteScript() throws an exception but runs fine when the page is an htm or html.
farmas
Participant
1164 Points
259 Posts
Microsoft
Using LTAF to automate a page with frames.
Apr 20, 2009 02:12 AM|LINK
(ported from CodePlex)
Hi,
I am evaluating this framework with my application and so far I am not able to use it for the reason mentioned below:
My application has UI framework consisting of frames. Also, lots of UI related common info like height, width, top level navigation links etc is part of top level frame. And this info is being reffered in child frames/pages as "top.variable" or "top.function" etc.
If I use this LTA framework, my top level frame is replaced by a frame from this LTAF frame. Clearly, the info that my app is looking for is not a part of LTA Framework and hence it ends up with lots of script errors.
Changing my app would not be feasible because of the large scope of the changes, probably entire app.
Does anyone has any idea/comment on resolving this issue with minimal changes in LTA Framework itself?
farmas
Participant
1164 Points
259 Posts
Microsoft
Re: Using LTAF to automate a page with frames.
Apr 20, 2009 03:14 AM|LINK
Hello,
If your website depends on frames referencing their parent, then most likely you want to navigate to the whole frameset, and then automate only one of the frames.
Automating frames in LTAF is a feature that will be included in our next release. However, the core functionality is already included in the April release, what's missing is a way to expose it by our API. The changes to enable it are very simple
1. Le's suppose that you have a "FrameSet.htm" that loads 2 separate pages into frames:
<html xmlns="http://www.w3.org/1999/xhtml"> <frameset rows="50%,50%"> <frame name="topFrame" src="TopPage.htm"> <frame name="bottomFrame" src="BottomPage.htm"> </frameset> </html>And the content of "TopPage.htm":
2. Assuming that the majority of your application is loaded into the top frame, then you want LTAF to navigate to the frameset and then to target the top frame for all subsequent actions. To enable this, modify HtmlPage.cs as follows:
2.1 First we need a small flag to indicate if we have navigated to the frameset. You want to turn this on at the end of the current Navigate method.
2.2 Next, you modify the ExecuteCommand method to check if this flag is set, and modify the command to add the frame information:
3. Now you can automate a test agains the topFrame regularly:
[WebTestMethod] public void FrameTest() { HtmlPage page = new HtmlPage("FrameSet.htm"); HtmlElement span = page.Elements.Find("SpanInFrame"); Assert.AreEqual("This is the top page", span.GetInnerText()); page.Elements.Find("ButtonInFrame").Click(); Assert.AreEqual("Button has been clicked", span.GetInnerText()); }That's it. You'll notice that in step 2.2 I hard coded "topFrame" in there, but you could very easily store the name of the frame in some variable that you initialize when constructing the HtmlPage.
Some closing comments:
- If you need it, I can send you a private with this fix.
- For next release, this functionality will be exposed by a public "GetFrame" method on HtmlPage, so that you could write:
HtmlPage framesetPage = new HtmlPage("frameset.htm");
HtmlPage topPage = framesetPage.GetFrame("topFrame");
Hope it helps, let me know if this is not what you meant by your original post.
- Federico
farmas
Participant
1164 Points
259 Posts
Microsoft
Re: Using LTAF to automate a page with frames.
Apr 20, 2009 03:19 AM|LINK
An update:
For next release a lot of the methods in HtmlPage will be marked as virtual to make it simpler to extend. When that happens, one will be able to inherit from HtmlPage and override the ExecuteCommand method to modify the command just before it is sent to the browser.
This is another way to accomplish the modification that I posted above.
- Federico
FRMJiggs
Member
4 Points
5 Posts
Re: Using LTAF to automate a page with frames.
Apr 20, 2009 03:31 PM|LINK
Federico,
Thanks for your quick response.
Your suggestion surely helps in one of my scenarios but it doesnot address my main concern. Let me explain my situation with help of sample code below:
<HTML xmlns="http://www.w3.org/1999/xhtml"> <SCRIPT language=javascript type=text/javascript src="/JavaScript/Global.js"></SCRIPT> <BODY> <SCRIPT type=text/javascript> //<![CDATA[ function _hdrRaisePopup() { if (typeof (top.PopupWindow) =='function') { //in LTAF, error occurs here top.PopupWindow('/samplepage.aspx', 800, 600); //('top' refers to LTAF frame instead of main window where JS file is included) } else if (typeof (top.ShowPopupWindow) =='function') { //same here top.ShowPopupWindow('/samplepage.aspx', 800, 600) //same here } else { alert('Unable to raise popup window'); } } //]]> </SCRIPT> <div> <IFRAME style="WIDTH: 240px; HEIGHT: 660px; TOP: 55px; LEFT: 0px" id="id1" src="/menupage.aspx" name="navMenuFrame" ></IFRAME> <IFRAME style="WIDTH: 1352px; HEIGHT: 940px; TOP: 55px; LEFT: 244px" id="id2" src="/mainpage.aspx" name="mainFrame" ></IFRAME> <IFRAME style="WIDTH: 1352px; HEIGHT: 0px; TOP: 995px; LEFT: 244px" id="id3" src="/detailpage.aspx" name="detailFrame" ></IFRAME> </div> <!-- Other HTML elements ... --> </BODY></HTML>On line 2, external JavaScript is referenced and appended in top-level window of the browser.
Now, when frames on line 23, 24, and 25 are navigated to respective pages, script error occurs same as mentioned on line 9, 10, 12 & 13.
So basically, in javascript code wherever is the reference of 'top' keyword, it will not work as 'top' refers to the LTAF frame instead of my app's main frame window.
I hope I am clear enough to explain my situation.
Kindly post any further questions
Thanks,
Jignesh
- Jignesh
farmas
Participant
1164 Points
259 Posts
Microsoft
Re: Using LTAF to automate a page with frames.
Apr 20, 2009 06:37 PM|LINK
Oh, I get it now. Yeah, this is a problem with LTAF right now.
One work around is to use the new popup window support to have your pages run in their own window instead of inside LTAF's frame. You can accomplish this by writting something like this in your test code:
[WebTestMethod] public void AutomaticPopup() { // navigate to some page so that you can run scripts HtmlPage p = new HtmlPage("SomeRandomPageInYourSite.htm"); // execute a script that opens a new window that loads your real site p.ExecuteScript("function openWindow() { window.open('../TheRealPage.htm'); return true;} openWindow();"); // get the popupwindow and automate against it. HtmlPage newPage = p.GetPopupWindow(1); Assert.AreEqual("This is the page", newPage.Elements.Find("body", 0).GetInnerText()); }Although I verified that this works, it is far from optimal because you don't want each test to open a new window. However, if this approach works for you, one thing that we could do is add a feature to LTAF where all your tests run on the new window. What this would do is before start running any tests, it will automatically create a popup window by the technique that I showed here, and all your tests will run against that window instead (the test code will look the same).
Let me know what you think,
Federico
FRMJiggs
Member
4 Points
5 Posts
Re: Using LTAF to automate a page with frames.
Apr 28, 2009 05:55 PM|LINK
Hi Federico,
Lately I needed to focus on some other stuff in our project so I couldn't proceed with your test code.
Now that I tried it and found that It still doesnot work as it is trying to execute the script in the testFrame context and eventually ends up with the following JS exception:
Test Stack Trace:
<div style="BACKGROUND-COLOR: white; WIDTH: 100%; FONT-FAMILY: 'Verdana'; COLOR: black; FONT-SIZE: 8.5pt">Error in Test 'UserManagementTests.SignInAndSignOut'
Exception was thrown by the client engine: "[TestExecutorException]: Unhandled JS exception while executing command handler function ExecuteScript. (Details: {\"name\":\"TypeError\",\"message\":\"Object doesn't support this property or method\",\"number\":-2146827850,\"description\":\"Object doesn't support this property or method\"})" when running command: ExecuteScript on the target: < id=, index: 0>.
Exception Details: Microsoft.Web.Testing.Light.WebTestException: Exception was thrown by the client engine: "[TestExecutorException]: Unhandled JS exception while executing command handler function ExecuteScript. (Details: {\"name\":\"TypeError\",\"message\":\"Object doesn't support this property or method\",\"number\":-2146827850,\"description\":\"Object doesn't support this property or method\"})" when running command: ExecuteScript on the target: < id=, index: 0>.Source Error:
Line 14: Line 15: // execute a script that opens a new window that loads your real site Line 16: page.ExecuteScript("function openWindow() { window.open('Login.aspx'); return true;} openWindow();"); Line 17: Line 18: // get the popupwindow and automate against it.Source File: c:\v5\Www\UI\App_Code\Tests\UserManagementTests.cs Line: 16 Method: UserManagementTests.SignInAndSignOut()
Stack Trace:
Version Information: Microsoft .NET Framework Version: 2.0.50727.3082; ASP.NET Version: 2.0.50727.4005; ASP.NET AJAX Version: 3.5.30729.196; Microsoft.Web.Testing Version: 1.0.0.0</div>
My web test method looks like as below:
[
WebTestMethod] public void SignInAndSignOut(){
// Navigate to the login page HtmlPage page = new HtmlPage("TrueBlank.aspx"); // execute a script that opens a new window that loads your real site page.ExecuteScript("function openWindow() { window.open('Login.aspx'); return true;} openWindow();");
// get the popupwindow and automate against it. HtmlPage newPage = page.GetPopupWindow(1);
// Fill Login control user/password and click login button page.Elements.Find("UserName").SetText("UItestUser");page.Elements.Find(
"Password").SetText("password"); page.Elements.Find("butLogin").Click(WaitFor.Postback); // Verify content of the Home page Assert.AreEqual("Application Home Page", page.Elements.Find("slblApplicationHomePage").GetInnerText()); // Click the logout link page.Elements.Find("shlLogout").Click(WaitFor.Postback); // Verify login button now exists. Assert.IsTrue(page.Elements.Exists("butLogin"));}
I traced back to the LTAF code where it was failing:
Can you provide some other insight?
Besides this, yes, it would be of great help if we can run the tests in new windows. Also, currently, test running frames can be used to display outputs/exceptions/logs etc instead.
Waiting for your response...
- Jignesh
farmas
Participant
1164 Points
259 Posts
Microsoft
Re: Using LTAF to automate a page with frames.
Apr 29, 2009 05:44 AM|LINK
Unfortunately, I could not repro this problem on my side, so maybe I am doing something different. I am assuming your browser settings enable popup windows from script? Could you let me know what browser your are using?
I am interested in investigating this to see if there is a bug on our side, can you email me so that I can send you what I have to see if it works on your environment? Mail is farmas@microsoft.com
Thanks!
- Federico
AikiBushi
Member
6 Points
9 Posts
Re: Using LTAF to automate a page with frames.
Jul 15, 2009 07:21 PM|LINK
I just came across this issue. It appears that when page = *.aspx then ExecuteScript() throws an exception but runs fine when the page is an htm or html.
Is there a work around?
farmas
Participant
1164 Points
259 Posts
Microsoft
Re: Using LTAF to automate a page with frames.
Jul 15, 2009 08:20 PM|LINK
Interesting. I'll look into it. Are you still using frames?
AikiBushi
Member
6 Points
9 Posts
Re: Using LTAF to automate a page with frames.
Jul 15, 2009 10:16 PM|LINK
No frames. Just using a custom test ASP.NET app to prototype an automation structure.