Forum Discussion
If you are going to record anything and everything ..yes it's not an efficient way of creating automation script.
Now in your example you do repetitive operation ie. you add and submit "Hello(i)" 100th time
where (i) is 1 to 100.....
hear the idea is to write a single script for all your 100 operation which can run 1 to 100.
this could be achieved with couple of things
1) Using Wildcards in Name Mapping
so you can use wild card in name-mapping such that it could identify any of your "ADD", "text box" and "submit" using wild card eg
parent.children.item(i).QuerySelector(XXX)
and with DDT you can put any value instead of "Hello 1" and with for loop run it 100 times changing i (1 to 100).
Please go-through above links and try your self. any practical problems forum can help
Thanks for the reply.
In name mapping , I can see that everytime user click the "ADD" button , a new cell will be created under the parent "table" and that cell now has a unique properties (RowIndex and ColumnIndex).
That is very helpful because now I know when I click the ADD button for the first time, I can expect a cell with Row "1".
If I click the ADD button for the second time, I can expect two cells with row "1" and row "2".
But how can I wildcard this property and put it in my JS script?
If I put like this in my script
Aliases.browser.xxx.yyy.zzz.table.cell ;
It will refer to the cell in row "1"
After I click the ADD button for the second time, how can I ask TC to please search for cell with row index = row index + 1 ?
Assume that cell11 has row index "2" , can TC search for cell with Row Index = '2' , after clicking the ADD button for the second time?
Thank You.
- Colin_McCrae9 years agoCommunity Hero
OK.
Between your first post, and your second post, you added some important information.
The initial post mentions nothing about a table. Your second one does. As soon as you have a table, you are dealing with rows, columns and cells. It sounds like your text boxes are being added to a cell in a table.
So your object hierarchy now becomes:
- Page
- Table
- Cell 1
- TextBox
- Cell 2
- TextBox
- Cell 3 (Empty?)
- Cell 4
And Row and Column may be in there as well. Or the cells may be children of the table. Or found as an object within a property of the table. There are various different table types and they are populated and rendered in many different ways. It's impossible to say for sure without inspecting it or knowing exactly what it is.
What I would say though, is that individual cells are seldom worth mapping. The table itself I would map. The cells within it, I would not as they tend to be too dynamic. Things move around, content changes etc etc.
I would probably end up with the table object mapped, and a sensible Alias applied. (Aliases should be much more concise and readable than full object names. They should NOT be a straight copy of the full object reference!) And then helper functions to find and manipulate the cells and their contents within it. In fact, I have things set up EXACTLY that way in my current project!
Going back to how you could handle several instances of a similar button - I think you may be coming at it from slightly the wrong angle. You use the wildcards in the identification properties of the mapped object to account for things which are dynamic at runtime. So if the table "Name" property (for example) had some sort of timestamp in it which changed every run, you would replace that with a "*" to allow it to still identify correctly.
https://support.smartbear.com/screencasts/testcomplete/wildcard-dynamic-property-in-testcomplete/
Using a single mapped object to try and control multiple on screen objects is not a great idea as that is ambiguous by it's nature. How do you know you have the right instance? And if there are more than one present on screen, you'll get an ambiguous mapping error as it won't know which one it should be using.
Mapping isn't always the right way. With table cells, and their contents, it's almost never the right way in my opinion.
- coffee9 years agoContributor
Thank you very much Colin_McCrae :smileywink:
I did some research and found out that this method works
var props = ["RowIndex" , "ColumnIndex"]; var values = ["1" ,"3"]; var depth = 0; var box = parent.FindChild(props, values, depth);
Basically I mapped the parent , because the parent is static, and then FindChild will find the cell that will be generated once "ADD" button is clicked.
I think for this case , I am very lucky, because for some reason TC can recognize the RowIndex and the ColumnIndex.
The combination of RowIndex and ColumnIndex will make that particular cell unique and identifiable.
I am just wondering if there is no such unique identifier nor nothing can be combined to make that cell unique , then how would this kind of challenge be solved?
I haven't used TC that long, but I am pretty sure that such cases (where no unique identifier can be identified) do exist.
If the UI Developer can be approached to give us some "hook" for TC, then that would be awesome, otherwise ... not sure what can be done here ???
Moreover, I am also not sure how TC can recognize the RowIndex and ColumnIndex , because when I analyze the DOM, there is no such Row Index nor Column Index for those cells ... Not sure how TC does the magic here ...
Thanks.
- Colin_McCrae9 years agoCommunity Hero
As ever, things are seldom that simple.
If you had a table, full of cells, and some of those cells contained a button, but they were all the same button, then you would probably have to use row and/or column headers to find the right one. You can't always go direct!
I do exactly this with web tables as they are way too dynamic to expect things to be in the same place all the time. They are used running tests with user driven data which allows the user to add and delete data/rows from many of these tables.
So I don't go directly to a cell.
I search the column headers for a match. (User has to supply this ref). Then I do the same with the row. This gives you your co-ordinates within the grid. Then it takes whatever the appropriate action is on the cell.
Using indexes for anything is generally not a good idea. You're not searching for anything specific to an object if you do this. You're simply saying - go to X/Y and a button should be there. If it moves, you need to update things.
I suppose, at the end of the day, it depends how "fixed" the path of your test is. If is has a defined start point, defined data, and a defined path of actions to get to that point, and these will NEVER change, then it should work. I work with people who run tests like this. But mine is a user data driven framework. It's way more variable and dynamic. So this model would never hold up for me.
As for unique identifiers .... normally, you can always find something. If all else fails, you can use relationships to other objects, positional data (not just co-ordinates, but positions relative to the parent app, siblings, whatever), I've ended up using OCR and image matching for some things (no other choice). There are usually many ways to skin a cat! If you end up with an app/site with 20 identical buttons, which all do the same thing, and are not different in and way, shape or form, then your design team has gone crazy. :) Why would anyone ever build that? (A grid with 20 buttons - all the same - and no column or row headers would a good example!) Getting your devs to add info to unused properties to allow you to identify things is great if they are willing and able to do so. What they can add and where is entirely dependent on the controls they're working with.
In web terms (I'm more used to dealing with desktop application tables .... which can be MUCH more complex than any web based one I've run it), I'm not sure how much of the identification data is native, and how much of it is added/implied by TestComplete. In desktop world, rows/columns/cells are usually constituent parts of the overall table object. The cells are seldom objects in their own right.
What you're finding out though, is not everything is worth mapping. Which I would agree with.
Much like you've done here .... I tend to map the larger, static parts of anything I test. And use helper/finder functions on the smaller, dynamic/variable parts. Once you get the balance right, and your mapping criteria solid, it works well.
- AlexKaras9 years ago
Champion Level 2
Hi,
While I think that .FindChild() and the like is a better approach, but if you really like to use namemapping, you may consider the fact that it is possible to use project variables instead of constant values for the values of identifiers (https://support.smartbear.com/testcomplete/docs/testing-with/object-identification/name-mapping/managing/modifying/identification-properties.html).