Buildup and reference of objects in HP UFT - vbscript

I'm wondering how I can access properties/methods via console/watch.
I have the following code:
Dim page
page = Browser("Welcome: Mercury Tours").Page
Now I want to obtain the title of this Page. Since I inspected the Page object with Object Spy and I saw it has a title property.
When I enter page.title in my watch however, it tells me that page does not contain the property.
1. What is the correct syntax?
2. Why is this not working? I presume that the watch is checking for VBScript object properties instead of TestObject properties?
(I have a programming background and I find it very confusing that I have VBObjects and TestObjects simply walking through the same file. It kind of feels like a black box :/)

Ok, well, your syntax is incorrect...
It appears that you're trying to put something into a variable called "page", but I'm not sure if I can figure out your intention.
If you are trying to put the page object into the var "page", you would need to use a set statement (to indicate to vbscript that it's going to hold an object, not just a single piece of data)...
Regardless of that, your syntax for specifying the Page is wrong.
In your example, you're specifying a browser test object called "Welcome: Mercury Tours" from the repository... but then you put .Page - and that's where your syntax error is.
It helps to understand the difference between Test Objects and Realtime Objects - because you need to specify a page Test Object. You can do that by specifying a page object from the Object Repository, or you can do it descriptively.
Test Objects are descriptions of real objects that QTP tries to find. If it successfully finds a real object that matches the description, then the Test Object kind of (virtually) "attaches to" the real object... then, you can use the test object to query the real attributes of the real object that it attached to.
Sincel you're clearly doing the tutorial, your object repository probably has a Page test object in the heiarchy under the browser object... (and if you had let Intellisense help, it would show you a list of pages to choose from while you type...). If so, you would specify the page object like this:
Browser("Welcome: Mercury Tours").Page("PageObjectNameHere")
If you would prefer to use descriptive programming, you could instead type something like:
Browser("Welcome: Mercury Tours").Page("Title:=Welcome: Mercury Tours")
Changing your syntax to either of those constructs would let you proceed with the next part of solving your question - how to get some data from the page...
So, once you have address the page test object correctly, then you can specify a method to get information from it... such as .GetROProperty()
You can choose from many properties for a page... If you examine a page using GUISPY, it pretty much gives you a list of the properties available to query... For example, if you want to check the URL of the page that's displayed, you could specify
Browser("Welcome: Mercury Tours").Page("Title:=Welcome: Mercury Tours").GetROProperty("url")
This, of course returns a value, so you want to do something with it... like assign it to a variable
result = Browser("Welcome: Mercury Tours").Page("Title:=Welcome: Mercury Tours").GetROProperty("url")
(If you do this, you can then add the variable "result" to the watch list... which answers your question.)
or examine it directly in your code
if Browser("Welcome: Mercury Tours").Page("Title:=Welcome: Mercury Tours").GetROProperty("url") = url_to_compare then DoSomething()
I hope this helps to clear up your understanding :)

Related

Following Test Automation best practise of "Methods return other PageObjects" in Ruby

I am a big advocate of the Page Object Pattern (POP) as defined by the experts at Selenium:
https://code.google.com/p/selenium/wiki/PageObjects
A key view of theirs that I have always followed when using Appium with Java is:
"Methods return other PageObjects"
e.g. LoginPage loginPage = homePage.gotoLoginPage();
I am now trying to following POP using Calabash with Ruby and so have been writing code like this:
e.g. #login_page = #home_page.goto_login_page
However, since Ruby doesn't know what type of object #login_page is or #home_page is, you dont get any of the benefits of intellisense showing what methods are available for a given page.
Anyone know a good way around this?
As much as I appreciate and apply PO design pattern, as much I disagree with returning page object by page object. Page object should be independent and don't need to know about other page objects. Look at two examples:
You test form validation. Click on submit button returns page object which is subsequent in the workflow, but in this case you remain on page with validation errors. Your page object won't know about it and will return the other page.
Page which you get to after clicking a button may differ depending on the context (e.g. from what other page you got to current page). It can lead to having multiple versions of actually same method, which will return different page objects depending on context. This is not good and overcomplicates simple thing.
If you want to return current page object, you can benefit from it e.g. in Java, when you return this at the end of the method. Then you can chain all methods you execute as long as you are on the same page. But when it comes to the question 'how to implement returning different page objects' - answer is simple - 'just don't'. Please note wiki entry you quoted has not been updated for a good while and best practices has evolved since it was originally published.
It seems like you already have your solution. However for others and perhaps also for you the x-platform approach to calabash uses page objects so you could check out that implementation https://github.com/calabash/x-platform-example
An alternative method would be as follows. Not as neat as I would like (given the need to manually create new instances of subsequent pages), but available as an alternative option:
When(/^I buy a movie from the movie page$/) do
movie_page = MoviePage.new
movie_page.buyMovie("Test Movie")
purchase_page = PurchasePage.new
purchase_page.confirmPurchase
end
Found a way of getting this to work after much research and applying well known Java/C#/Obj-c principles to Ruby:
Given(/^I am on the launch page$/) do
#launch_page ||= LaunchPage.new
end
When(/^I open the set alarm time page$/) do
#set_alarm_page = #launch_page.goto_set_alarm_page
end
When(/^I open our apps from the home page$/) do
#launch_page.navigation_toolbar.open_our_apps
end
Then(/^I should see the homepage alarm time is (\d+)$/) do |alarm_time|
alarm_time_actual = #launch_page.get_alarm_time
assert_equal(alarm_time, alarm_time_actual)
end
As long as somewhere on the step definition class you explicitly create a new page object (in the above example: LaunchPage.new), then all subsequent pages will provide intellisense method/property values, since the resulting page types returned will be known by RubyMine.

Record without adding to repository?

Imagine creating a new QTP project. You hit record to get your first bit of code in place. By default, you'll get something like:
Browser("MyApp").Page("MyPage").WebEdit("MyLogin").Set "Bob"
And you'll get the Browser, Page, and WebEdit objects automatically added to the repository. What I would like to be able to do, as one of those QTP bods that prefers descriptive programming, is hit record, and get something like:
Browser("name:=MyApp").Page("name:=MyPage").WebEdit("name:=MyLogin").Set "Bob"
And have no objects added to the repository. Is there a setting / option to do this somewhere?
(Obviously there are arguments for not wanting to do this, which I acknowledge and appreciate - but for those of us that prefer DP, this could help expedite test creation).
From what i understood is that you want to hit 'Record' button and you will get the script in descriptive type rather than the usual. But that is not possible.
For descriptive programming, you have to explicitly write the code by identifying the properties of each object for that (you can use Tools > Object Spy).
For above example:
Go to Object Spy > Select "the pointing hand symbol button" and click on the WebEdit for which you want to set the text "Bob"
Now, from Object Hierarchy select each object Top to Bottom and write properties of those object in the script. Like 1st Browser, then Page, then WebEdit. Try adding as more properties as you can.
You just can not get descriptive script by hitting Record button.

How can I find the page object of the page watir is currently on?

Context:
I'm trying to make reusable step definitions that click on page objects on the current page,
e.g. (cucumber step def follows):
When(/^the user clicks the "([^"]*)" button$/) do |button|
click_button = button.downcase.gsub(" ","_")
#current_page #somehow get current page object on this line
#current_page.click_button
end
Problem statement:
I can't find anything that returns the current page object.
An explanation for why the obvious solution didn't work:
I thought #current_page was already there as something I could use. I looked in the source code for page object, and the variable #current_page does exist. Not sure how to use it if I can...
BTW, in this case, I have a bunch of testers that can write Gherkin but not necessarily step definitions. We are trying to rapidly finish a bunch of regression tests for an in house app with an unchanging interface.
This is somewhat at odds with what page-object is trying to provide.
Page object attempts to provide well named actions for interacting with a specific page. If you are wanting to make something that works in general against any page, it will be much easier to write it with watir-webdriver directly.
That said, I agree that a specification based heavily on implementation like that is likely to change. I also would add that it doesn't add much value. I would only continue down this path if you understand and accept that you are using cucumber as a test templating tool instead of a requirements communication tool.
As Justin Ko mentioned, #current_page gets set when you call the on or visit methods. Its not a good idea to lump something that changes the page object in a step that performs a specific action (in this case clicking a button). You might want a different step that indicates the behavior of the application, such as
the application lands on the <your page> page
Then you're can use the name of the page object class to load #current_page via the on method in that step definition. This also gives the benifit (or curse of having your step having more lower level details) of indicating expected page navigation behavior.

Google Analytics not tracking conversions in Magento 1.7

I'm using Magento's built in Googleanalytics module which is working fine for page views, but not for conversions. The account is set up fine on Google, but it's not adding the addTrans part in the checkout/onepage/success page.
I've done a lot of digging this morning, and found that the observer does observe the "checkout_onepage_controller_success_action" correctly, and does indeed run. It does the following:
$block = Mage::app()->getFrontController()->getAction()->getLayout()->getBlock('google_analytics');
if ($block) {
$block->setOrderIds($orderIds);
}
I've done some echoing, and it does retrieve the block, and it also sets the order ids correctly. However, in the block itself, if I echo out $this->getOrderIds(); its empty.
My next thought was that perhaps it could be using two GA blocks on the page, and maybe its passing the data to the first one but echoing the HTML of the 2nd one, but I've no clue how to start checking that! The Googleanalytics.xml file only has one block it in, and I don't use that block name anywhere else!
Anyone experienced similar? Or have any idea where I can go from here?
EDIT:
The Ga.php block includes the transaction code if $this->getOrderIds() returns an array, which it is not doing. However, the observer is doing $block->setOrderIds($order_ids); which is passing through an array containing an order id. So the observer is passing the ids to the block, and the block is receiving them (setting up a method of setBlockIds and echoing out the argument, does show the array), but when the block tries to access its own data, it's suddenly not there ($block->getData() returns an array of properties but there is no order_ids property).
I also figured maybe it could be that its echoing the blocks HTML before setting the order id, so I added some variables in to check that and it's not that - its definitely setting the order_ids before trying to get them again, but its still not working!
I'm completely stumped! My only idea now is to modify the Ga.php block to use Magento's registry instead of it's own _data property, which is really not a nice way of doing it!
I think i've been an utter tool. Magento wasn't tracking conversions on the live site because I hadn't put the account code in the configuration part, but I had on my test site.
I had previously put my own analytics code in the template, so I had tracked page views.
When I saw no conversions (despite putting the account code in my test site), I started making orders on the test site and then viewing the source of the order success page. Firefox loads its source as a new request...which automatically goes to the empty basket page. So obviously, it wasn't showing the addTrans or anything, because it had already done that.
A quick check in firebug revealled it was working as it should.
So in the end, after a day of searching, I had to change "No" to "Yes" in the admin, and type in the account code. Great.

Changing Views in a Module pops me into the Admin Skin

This question has probably been the most covered question in all of DotNetNuke's lifetime but I'm going to ask it here in StackOverflow because I need an answer, a really good one that doesn't make me look the other way. Thanks in advance to all DNN experts.
I've researched many ways of making this work for me and i've seen Michael Washington's solutions (Panels, MultiViews, ...) and Will's (Strohl) blog post on DotNetNuke's personalization engine through setting SkinSrc which is useful, as well as reading through Default.aspx's code which has given me more insight, however, i'm still faced with the problem that calling EditUrl()/NavigateUrl() brings me to a page with a single module in admin skin or a page with nothing respectively.
The specific version is DotNetNuke 6.0.1 (DNN). This Module has 4 other views in addition to the main view which I desire to navigate through sequentially. e.g.
Begin Checkout -> Collection of Delivery Details -> Confim Order
Have you found a solution?
I want to achieve
1) Module loads with other modules around. No module isolation
2) Views in a module that don't Preload e.g. Page_Load in each view gets called when the Module loads up
Help!
Assuming you are asking this as the module developer, the solution is to not use DNN's mechanism for specifying a control. So, you can't use EditUrl or specify the ControlKey in the NavigateURL call (which both generate "ctl=mycontrol" in the URL). Instead you need to have your module display your various controls based on the Query String parameters. So, you'll generally have a control in your module who's primary purpose is to dynamically load other controls based on the query string. So, for instance:
You will start with your control that lists items. You'll have a "Buy Now" button for each item. The hyperlink for each item can be generated by calling
NavigateURL(TabID, "", "View=BeginCheckout", "itemid=" & id, "mid=" & mid)
2.) On the page load of the handler control, it looks to see if anything is specified for the "View" Querystring parameter. If not it displays the listing control, if so, it displays the corresponding control.
Dim controlPath As String
Dim path as String = "~/DesktopModules/MyModule/Controls"
Select Case Request("View")
Case "BeginCheckout"
ControlPath = path + "BeginCheckout.ascx"
Case "DeliveryDetails"
ControlPath = path + "DeliveryDetails.ascx"
Case "ConfirmOrder"
ControlPath = path + "ConfirmOrder.ascx"
Case Else
ControlPath = path + "ItemList.aspx"
End Select
If System.IO.File.Exists(Request.MapPath(controlPath)) Then
placeholder.LoadControl(controlPath)
Else
Throw New Exception("Unable to load selected template. Please go into module settings and select a list and details template.")
End If
Most of the advanced modules for DNN do something along these lines so there's plenty of sample code out there. I would guess some of the core modules do something similar. I adapted the code above from Efficon's Articles module for DotNetNuke.

Resources