From davids at tower-mt.com Thu Jun 1 16:23:14 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 01 Jun 2006 13:23:14 -0700 Subject: [Wtr-development] [Wtr-general] Determine HTML property In-Reply-To: References: Message-ID: <447F4CB2.6070902@tower-mt.com> Zeljko Filipin wrote: > ie.radio(:id, "id").readonly? > > On 6/1/06, *Adrian Rutter* > wrote: > > > Hi, > > I have an HTML field that once saved becomes read-only > [readonly="true"]. > Apart from doing a regex on the source how can I determine this > property? > > Cheers > > Aidy > I've just encountered a situation where this doesn't work, and written a fix for it, though I'm not sure where this fix would best be integrated. The problem is that while an input element may NOT be read only, a containing element like a table cell, table row or div may have their visibility turned off, which prevents Watir from setting the focus on the input element and effectively makes the input element read only even though the readonly attribute is false: irb(main):014:0> ie.text_field(:id, 'Detail_Date').readonly? => false irb(main):015:0> ie.text_field(:id, 'Detail_Date').set('01/01/2000') WIN32OLERuntimeError: focus OLE error code:800A083E in htmlfile Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus. HRESULT error code:0x80020009 Exception occurred. from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `method_missing' from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `set' from (irb):15 In this case, a TR element a few levels higher has a style of "visibility: hidden; display: none" so the control is invisible and thus read only. I see a few solutions. The first would be to try to update the input element and then rescue the WIN32OLERuntimeError exception. I'm not particularly fond of this, especially since the exception isn't an exception specific to this problem. Another option is to iterate up the DOM elements checking every element to make sure that is is visible. This could be done in Element#readonly?, but then we wouldn't be able to see the value of the actual readonly attribute. I chose to implement another method which I called "writable?" which first checks that the element exists, is enabled and not readonly and then moves up the DOM tree and reports false if any element is not visible (visibility != 'hidden' and display != 'none'). I've tested this and while it can be slow if the input element is deeply embedded it *does* seem to be accurate: irb(main):016:0> ie.text_field(:id, 'Detail_Date').writable? => false irb(main):017:0> ie.text_field(:id, 'Detail_DOB').writable? => true You can try this by adding the following method in your Watir script or by adding just the writable? definition inside class Element in Watir.rb. I can add this to trunk once I get some tests written to test it if we decide this is the way to go. Does anyone have a cleaner or faster way to do this? module Watir class Element # Determine if we can write to a DOM element. # If any parent element isn't visible then we cannot write to the # element. The only realiable way to determine this is to iterate # up the DOM elemint tree checking every element to make sure it's # visible. def writable? assert_exists # First make sure the element itself is writable begin assert_enabled assert_not_readonly rescue Watir::Exception::ObjectDisabledException, Watir::Exception::ObjectReadOnlyException return false end return false if ! document.iscontentEditable # Now iterate up the DOM element tree and return false if any # parent element isn't visible or is disabled. object = document while object begin if object.style.invoke('visibility') =~ /^hidden$/i return false end if object.style.invoke('display') =~ /^none$/i return false end if object.invoke('isDisabled') return false end rescue WIN32OLERuntimeError end object += '.parentElement' end true end end end From jared at kilmore.info Wed Jun 7 02:00:40 2006 From: jared at kilmore.info (Jared Quinert) Date: Wed, 07 Jun 2006 16:00:40 +1000 Subject: [Wtr-development] [Wtr-general] Watir 1.5.x Performance Issues? In-Reply-To: <4485EBA8.8040907@titanez.net> References: <4485EBA8.8040907@titanez.net> Message-ID: <44866B88.5010502@kilmore.info> Hi Bret, When you mentioned timeouts, were you referring to this line in watir.rb - DEFAULT_SLEEP_TIME = ...or to changes in the wait method? Or is it something else? I had a quick look/grep through the 1.5 source but wasn't sure. Jared >> >> I spend a lot of time tuning my test suites to make them run fast, >> without running so fast that they become unreliable. Typically, this >> involves tuning timeouts (which are in 1.5, but not in 1.4) and >> removing sleeps. Of course, i always run Watir in "fast mode". >> >> Bret > > ------------------------------------------------------------------------ > > _______________________________________________ > Wtr-general mailing list > Wtr-general at rubyforge.org > http://rubyforge.org/mailman/listinfo/wtr-general -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060607/8a7ec041/attachment.htm From davids at tower-mt.com Sat Jun 10 20:56:46 2006 From: davids at tower-mt.com (David Schmidt) Date: Sat, 10 Jun 2006 17:56:46 -0700 Subject: [Wtr-development] Table Row Bug -- How to fix? Message-ID: <448B6A4E.9080009@tower-mt.com> Hi all, I've been working on the Table Row bug, and I have some questions about what changes folks want. The bottom line issue is *when* to apply the fix. (Note that this applies to any DOM collection, not just table rows.) I now have code which can accurately count just the rows in the current table instead of all rows below a certain point in the DOM. Same thing with cells. However the code to retrieve a row or cell by :index also needs to be adjusted, but I'm not certain how best to do this. This is because there are two ways to look for rows. Watir allows you to find a row anywhere in the document like "ie.row(:index, 3)" or "ie.row(:id, 'xx')". The other way would be below a table or table-group ("THEAD", "TFOOT" or "TBODY") as in "ie.table(:how, what).row(:index, x)" or "ie.table(:how, what)[n]". Here's my question. Under which conditions should the selection of rows be restricted to just those in the current table, and when should the selection be for all rows below the current object? If we change which rows are selected using any methods we risk breaking existing scripts, but I would argue that certain methods should only consider rows in the current table. My current opinion is that when selecting a row by :index (or via []) we would restrict the selection to just those rows in the current table and ignore any rows in any sub-tables. When selecting by :id or :name it may still be appropriate to select all rows below the current element. I'd like to see some consensus before changing something that could affect existing scripts, but I do think there are times to restrict the selection to just the current table. David Schmidt From bret at pettichord.com Wed Jun 14 15:32:44 2006 From: bret at pettichord.com (Bret Pettichord) Date: Wed, 14 Jun 2006 14:32:44 -0500 Subject: [Wtr-development] timeouts Message-ID: > > Hi Bret, > > When you mentioned timeouts, were you referring to this line in watir.rb > - > > DEFAULT_SLEEP_TIME = > > ...or to changes in the wait method? > > Or is it something else? I had a quick look/grep through the 1.5 source > but wasn't sure. > > Jared > > I was referring to @@attach_timeout. My application makes common use of modal dialogs, which is affected by this. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060614/b2287f41/attachment.htm From bret at pettichord.com Wed Jun 14 17:06:19 2006 From: bret at pettichord.com (Bret Pettichord) Date: Wed, 14 Jun 2006 16:06:19 -0500 Subject: [Wtr-development] Table Row Bug -- How to fix? Message-ID: > > Hi all, I've been working on the Table Row bug, and I have some > questions about what changes folks want. The bottom line issue is > > *when* to apply the fix. (Note that this applies to any DOM collection, > not just table rows.) > > I now have code which can accurately count just the rows in the current > table instead of all rows below a certain point in the DOM. Same thing > > with cells. However the code to retrieve a row or cell by :index also > needs to be adjusted, but I'm not certain how best to do this. This is > because there are two ways to look for rows. Watir allows you to find a > > row anywhere in the document like "ie.row(:index, 3)" or "ie.row(:id, > 'xx')". The other way would be below a table or table-group ("THEAD", > "TFOOT" or "TBODY") as in " > ie.table(:how, what).row(:index, x)" or > "ie.table(:how, what)[n]". > > Here's my question. Under which conditions should the selection of rows > be restricted to just those in the current table, and when should the > > selection be for all rows below the current object? If we change which > rows are selected using any methods we risk breaking existing scripts, > but I would argue that certain methods should only consider rows in the > > current table. > > My current opinion is that when selecting a row by :index (or via []) we > > would restrict the selection to just those rows in the current table and > ignore any rows in any sub-tables. When selecting by :id or :name it > may still be appropriate to select all rows below the current element. > > > I'd like to see some consensus before changing something that could > affect existing scripts, but I do think there are times to restrict the > selection to just the current table. > > David Schmidt > > Before i get to David's specific question, let me make a couple of comments. 1. My apologies for the delay in responding. Next time I need to remember to subscribe to a new list when i create it. 2. The purpose of this list is to discuss the how of developing Watir. In other words, how to we make particular changes? What unit tests do we need? I've been finding the need to discuss the architecture of Watir and what i like and dislike about it and that kind of conversation doesn't really belong on wtr-general where we have people who still don't understand how to use assertions. 3. This isn't a good place to get approval for changes that will break existing user tests. Wtr-general is the place for that. But it may be a good place to get feedback on an idea before presenting it to that forum. Personally, i am trying to involve the community more in Watir design discussions and this has been a personal challenge. Now for David's question. 1. I think that it is pretty safe to change row_count to only count the rows that belong to a table. I said this on wtr-general and there was no dissent and i think i was understood. 2. I originally thought that changing Watir so that ie.table(x).row(y) would only reference rows that belonged to the specified table would be safe, but as i've thought more about it and reflected on how i've used Watir, i think that there is a pretty good chance that changing this would break tests. In our DataCert application, we make commonly reference tables as generic scoping containers and cells as types of objects. We wrap the watir calls in an abstraction layer, so this isn't immediatly clear to a scripter. But if we made it so that calls to cell() would be restricted to child cells when the container was a table, then that would probably break things for us. David's suggestion to use different semantics based on attribute is not appealing to me. For one, because it simply is too difficult to expect average users to understand. And secondly, because it seems to break down if we consider the possibility of multiple attributes, which i've started to commit code for, and am using for table cells, among other objects. The idea of multiple attributes offers another possibility: another attribute that specifies whether we should restrict the collection to child elements. Maybe ie.table(x).row(:belongs_to => true, index => 1). But i think i have a better idea. A new method, ie.table(x).child_row(:index => 1). A child_row would be just like another Row, except it would use a different locator method. Anyway, that is my proposal. It would mean adding child_row and child_cell to the Table and Row classes. It wouldn't break any tests. And i think that it would be pretty easy to understand. Only certain objects would have these methods, so it would be easy to tell (via the rdocs) which elements supported them. Regardless, of the interface, let me move to discussing how to implement them. This week i created a new Locator class (TaggedElementLocator) and i expect to be refactoring the code to create more. I've long thought that the locator methods, currently in the container class, really belonged in the element classes -- because it is the class of the element that determines what locator method is use. By creating separate classes for them, this ultimately facilitates this move. The urgent motivation for this change was that i needed to implement multiple attribute selection. But i also had this issue in mind as i worked on it. I think the right solution now mainly amounts to creating a ChildRowLocator and ChildCellLocator subclasses, refactoring TaggedElementLocator to isolate the call that now appears as the first line of locate and then create new ChildRow and ChildCell subclasses of Row and Cell, with modified locate methods. Since the child_row and child_cell factory methods (a factory method is a method that creates an object -- the def_creator class method that is used to create most of these factory methods is not a factory method, but rather a factory method factory, if you want to call it that) would only be defined for containers that make sense (Table, Row), there is no need to check the class of the container. In other words, not only is this approach pretty easy for users to comprehend, it is also fairly straight-forward to implement. However, the getElementsByTagName method is called from many different places within Watir, This is a code smell. One source of this duplication is the many show_* methods. Most could be replaced with simple calls to Collection#show. E.g. show_rows could be replace with rows.show (and child_rows.show). and one of the places is Container#locate_tagged_element, which uses getElementsByTagName for many different tag types. This is the call that is now delegated to the new Locator class. The problem > with this is that while the same method is used to get ALL tags of a > given type, each DOM element has it's own *specfic* method to return the > collection of specific child nodes (like "rows" for table rows, "cells" > for table cells, etc). > Right. So you need to change the locate method of ChildRows and ChildCells to use your new locators instead. (Just instantiate and call them directly in the element locate method -- there is no reason to include the container in the delegation chain. How does this sound? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060614/3aa99025/attachment-0001.htm From davids at tower-mt.com Wed Jun 14 20:00:35 2006 From: davids at tower-mt.com (David Schmidt) Date: Wed, 14 Jun 2006 17:00:35 -0700 Subject: [Wtr-development] Table Row Bug -- How to fix? In-Reply-To: References: Message-ID: <4490A323.8080502@tower-mt.com> Bret Pettichord wrote: > Now for David's question. > > 1. I think that it is pretty safe to change row_count to only count > the rows that belong to a table. I said this on wtr-general and there > was no dissent and i think i was understood. There may be a problem with just fixing row_count because of the way it is used. In addition, there is a problem with *which* rows will be retrieved even if the row_count is fixed to only show the row count for each table and ignore rows in sub-tables. The problem comes into play when you go to retrieve the rows (and this applies to any container for which there can be many sub-containers, like cells or divs). For example, in our current unit tests we have table1.html which contains a sub-table in one of the tables. I did a fix to the row_count and thought that things were fine when I did the following test: t = ie.table(:index, 3) # the table which contains another table t.rows.length => 2 t.rows.each {|r| puts r.html} That showed me the two rows in the parent table and I thought all was good. So, I made the same type of changes for cells and spotted a problem which affects rows too. The problem is that the elements returned by .each (from getElementsByTagName()) are returned in the order that they appear in the container element. For our table in table1.html they would appear as row1 of table3, row2 of table3 and then row1 of table4. When I only displayed the first two rows things looked fine. However, table4 (the sub-table) is located in row2, cell1, so when I used the same method to show cells for each row like this: t = ie.table(:index, 3) # the table which contains another table t.cells.length => 4 t.cells.each {|c| puts c.html} Instead of getting the 4 cells from table 3, I got: cell 1 # row 1 cell 1 cell2 # row 1 cell 2 # row 2 cell 1, containing the entire sub-table
nest1 nest2
nest1 # OOPS!, this is row 1 cell 1 the sub-table, table4. This is because the cells are returned in the order that they are seen in the HTML document, so the first cell of the sub-table (containing "nest1") appears immediately after cell containing the sub-table. In order to get the correct items we need to use a different method other than getElementsByTagName whenever we want *just* the directly child elements. > 2. I originally thought that changing Watir so that ie.table(x).row(y) > would only reference rows that belonged to the specified table would > be safe, but as i've thought more about it and reflected on how i've > used Watir, i think that there is a pretty good chance that changing > this would break tests. In our DataCert application, we make commonly > reference tables as generic scoping containers and cells as types of > objects. We wrap the watir calls in an abstraction layer, so this > isn't immediatly clear to a scripter. But if we made it so that calls > to cell() would be restricted to child cells when the container was a > table, then that would probably break things for us. > > David's suggestion to use different semantics based on attribute is > not appealing to me. For one, because it simply is too difficult to > expect average users to understand. And secondly, because it seems to > break down if we consider the possibility of multiple attributes, > which i've started to commit code for, and am using for table cells, > among other objects. The idea of multiple attributes offers another > possibility: another attribute that specifies whether we should > restrict the collection to child elements. Maybe > ie.table(x).row(:belongs_to => true, index => 1). But i think i have a > better idea. > > A new method, ie.table(x).child_row(:index => 1). A child_row would be > just like another Row, except it would use a different locator method. > > Anyway, that is my proposal. It would mean adding child_row and > child_cell to the Table and Row classes. It wouldn't break any tests. > And i think that it would be pretty easy to understand. Only certain > objects would have these methods, so it would be easy to tell (via the > rdocs) which elements supported them. > > Regardless, of the interface, let me move to discussing how to > implement them. > > This week i created a new Locator class (TaggedElementLocator) and i > expect to be refactoring the code to create more. I've long thought > that the locator methods, currently in the container class, really > belonged in the element classes -- because it is the class of the > element that determines what locator method is use. By creating > separate classes for them, this ultimately facilitates this move. The > urgent motivation for this change was that i needed to implement > multiple attribute selection. But i also had this issue in mind as i > worked on it. > > I think the right solution now mainly amounts to creating a > ChildRowLocator and ChildCellLocator subclasses, refactoring > TaggedElementLocator to isolate the call that now appears as the first > line of locate and then create new ChildRow and ChildCell subclasses > of Row and Cell, with modified locate methods. Since the child_row and > child_cell factory methods (a factory method is a method that creates > an object -- the def_creator class method that is used to create most > of these factory methods is not a factory method, but rather a factory > method factory, if you want to call it that) would only be defined for > containers that make sense (Table, Row), there is no need to check the > class of the container. In other words, not only is this approach > pretty easy for users to comprehend, it is also fairly > straight-forward to implement. > > > However, the > getElementsByTagName method is called from many different places > within > Watir, > > This is a code smell. One source of this duplication is the many > show_* methods. Most could be replaced with simple calls to > Collection#show. E.g. show_rows could be replace with rows.show (and > child_rows.show). > > and one of the places is Container#locate_tagged_element, which > uses getElementsByTagName for many different tag types. > > This is the call that is now delegated to the new Locator class. > > The problem > > with this is that while the same method is used to get ALL tags of a > given type, each DOM element has it's own *specfic* method to > return the > collection of specific child nodes (like "rows" for table rows, > "cells" > for table cells, etc). > > > Right. So you need to change the locate method of ChildRows and > ChildCells to use your new locators instead. (Just instantiate and > call them directly in the element locate method -- there is no reason > to include the container in the delegation chain. > > How does this sound? First, a couple of notes about the implementation above. This problem will occur in any container that can contain another of it's own kind as a sub-container. Unfortunately, while the getElementsByTagName is the method used by all the containers to retrieve ALL tags below the current point, the method used to get just the child elements has a different name for different containers, like "rows" for a table's direct rows, and "cells" for a tables direct cells. My first test implementation to fix the problem used the "children" method, which should be available from each container. One problem with writing a "generic" getChildElements is that rows and cells are NOT direct descendants of tables. Rows may be contained in THEAD, TFOOT or TBODY elements, and cells may be contained (http://www.w3.org/TR/html4/struct/tables.html). This means you have to put in special code to find all rows for a given table, or all cells for a given row because the rows will be children of a table child: irb(main):078:0> t.document.children.each {|child| puts child.tagName} TBODY irb(main):079:0> t.document.children['0'].children.each {|child| puts child.tagName} TR TR Even the DOM can be inconsistent at times. For example, check out all of the collections at http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/collections.asp. Some return ALL items in the document, others return all children below a container and some return only direct descendants of a container. The "cells" collection is even more interesting. If called from a table element it will return all cells in the current table, but if called from a row it will return just cells in that row (ignoring cells in sub-tables in either case). So, no matter what we decide to do, there will be a bunch of special code to handle special cases. Bleah. Second, I would like to see our methods match, as closely as possible, the DOM methods. This would imply that our "rows" method will return just the rows for the current table, and will ignore sub-tables. Obviously, this *will* break current tests. So, how about another way to do this which will maintain current functionality while adding new functionality and yet giving the users a choice of how they want the current commands to work. My suggestion is this. We implement Bret's suggestion above as getChildElementsByTag, using the current Watir method names with "child_" prepended. I.E., "table().child_rows", "table().child_cells", etc. We also implement method names to explicitly show the current functionality by prepending "all_" to each current method. I.E., "table().all_rows" or "table().all_cells" which would *by default* work just like "table().rows" and "table().cells". Lastly, we create a configuration variable which will allow testers to *change* which methods the old names use, with the default to be set to leave them as they are now. For example, "table().rows" would give ALL rows below a table, even rows in sub-tables unless (for example) the tester set @@collection_retrieval_style to "child", in which case "table().rows" would return only the rows in that table. "Row_count" (and "cell_count") would also have additional methods like "all_row_count" and "child_row_count" and the default would be the current "all_" method. We could then recommend that tests be coded to use the more explicit method names, and someday we could possibly change the default if we wanted, but for now all current tests would run as-is, but people desiring the "new" behavior could turn it on if they wanted, and people needing *both* behaviors would have ways to make that clear in their scripts by using "all_" or "child_" for all the methods. I'd recommend that we document *both* styles in a table which would show the equivalent DOM methods to make it clear what elements will be returned by each of the four methods ("all_", "child_", default(current), optional(by setting an option)). Current unit tests would run as they do now, but we could add unit tests for the "all_" or "child_" versions along with tests which would test the behaviors of the old commands with the configuration switched. I'll volunteer to do the implementation and can probably have some trial versions ready in a day or two. David From bret at pettichord.com Thu Jun 22 14:01:07 2006 From: bret at pettichord.com (Bret Pettichord) Date: Thu, 22 Jun 2006 13:01:07 -0500 Subject: [Wtr-development] Performance Improvement Message-ID: David, Thanks for the recent performance improvement http://svn.openqa.org/fisheye/changelog/watir?cs=1046 You may be interested to know that in Ruby 1.6, if you returned from within a WIN32OLE.each block, you got a LocalJumpError. That's why the pre-existing code was so inefficient. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060622/fcdd3102/attachment.html From bret at pettichord.com Fri Jun 23 11:33:10 2006 From: bret at pettichord.com (Bret Pettichord) Date: Fri, 23 Jun 2006 10:33:10 -0500 Subject: [Wtr-development] Performance Improvement In-Reply-To: References: Message-ID: I have another followup comment. 1046 created by > inetdavid on 22 June 2006, 02:39:36 -0500 (31 hours ago) (patch) > After profiling a web scraper that was running much slower with 1.5.1 than > with 1.4.1 > I found that 69% of the time was spent in locate_input_element(), almost > all of that time > in WIN32OLE#each. I saw that the each loop was continuing to run even > after an object > was found, so I re-wrote the loop so that the routine returns a value as > soon as one > is found and now that routine is only using 57% of CPU on the same test. > One problem with profiling is that it ignores the #1 cause of delay with Watir scripts -- sleeps. In general, i've made suites perform better by tweaking polling loops and reducing the time spent sleeping. But sleep-time is not counted as CPU time by the profiler, so it is effectively ignored. In other words, profiling makes code more efficient, but not necessarily faster. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060623/e5432ce1/attachment.html From davids at tower-mt.com Thu Jun 22 20:53:46 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 22 Jun 2006 17:53:46 -0700 Subject: [Wtr-development] Performance Improvement In-Reply-To: References: Message-ID: <449B3B9A.1080008@tower-mt.com> Even with that restriction, the "next" should have been a "break" to break out of the each loop as soon as a match was found. With the "next" the process looped over all values, even after a match was found. Glad to help though. We're seeing things running much slower under 1.5.1 so we're looking for things to speed up, and I may find some more for you. I'm also still waiting for an answer to the proposal for how to handle the collections count issues on wtr-development. David Bret Pettichord wrote: > David, > > Thanks for the recent performance improvement > > http://svn.openqa.org/fisheye/changelog/watir?cs=1046 > > You may be interested to know that in Ruby 1.6, if you returned from > within a WIN32OLE.each block, you got a LocalJumpError. That's why the > pre-existing code was so inefficient. > > Bret > ------------------------------------------------------------------------ > > _______________________________________________ > Wtr-development mailing list > Wtr-development at rubyforge.org > http://rubyforge.org/mailman/listinfo/wtr-development -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060626/d2d9ddaf/attachment.html From davids at tower-mt.com Mon Jun 26 18:57:45 2006 From: davids at tower-mt.com (David Schmidt) Date: Mon, 26 Jun 2006 15:57:45 -0700 Subject: [Wtr-development] Performance Improvement In-Reply-To: References: Message-ID: <44A06669.3030805@tower-mt.com> Bret Pettichord wrote: > I have another followup comment. > > 1046 > created by inetdavid on 22 June 2006, 02:39:36 -0500 (31 hours > ago) (patch > ) > > After profiling a web scraper that was running much slower with > 1.5.1 than with 1.4.1 > I found that 69% of the time was spent in locate_input_element(), > almost all of that time > in WIN32OLE#each. I saw that the each loop was continuing to run > even after an object > was found, so I re-wrote the loop so that the routine returns a > value as soon as one > is found and now that routine is only using 57% of CPU on the same > test. > > > One problem with profiling is that it ignores the #1 cause of delay > with Watir scripts -- sleeps. > > In general, i've made suites perform better by tweaking polling loops > and reducing the time spent sleeping. But sleep-time is not counted as > CPU time by the profiler, so it is effectively ignored. > > In other words, profiling makes code more efficient, but not > necessarily faster. > > Bret I'm using the latest ruby-prof gem (version 1.4.1) and it does account for time spent in Kernel#sleep. Watir::IE#wait was the biggest caller of sleep (as expected) with #until_with_timeout being the second biggest as I'm using it to watch AJAX "spinners" until they disappear before I fill the following field. My timers account for both of those with code that starts a timer before every click and then stops after a page (or AJAX update) is finished loading. Using WIN32OLE#each is a performance killer because OLE calls are relatively expensive. I doubled the speed of my scraper's screen filling with this change because almost all elements are located using :id or :name, and this patch lets Watir locate an :id object in one call, and a :name collection in one call plus one call for every element with that name. Only hassle is that getElementById will return an element that happens to have a matching name attribute, which may be what most people *want* to happen, but isn't entirely accurate and will break tests where there are two elements of the same type where one has an id attribute and the other has a name attribute that matches. David David From bret at pettichord.com Mon Jun 26 19:35:09 2006 From: bret at pettichord.com (Bret Pettichord) Date: Mon, 26 Jun 2006 18:35:09 -0500 Subject: [Wtr-development] Performance Improvement In-Reply-To: <449B3B9A.1080008@tower-mt.com> References: <449B3B9A.1080008@tower-mt.com> Message-ID: On 6/22/06, David Schmidt wrote: > > Even with that restriction, the "next" should have been a "break" to > break out of the each loop as soon as a match was found. With the "next" > the process looped over all values, even after a match was found. > A break inside the each block would also caused a LocalJumpError in Ruby 1.6 . > Glad to help though. We're seeing things running much slower under 1.5.1so we're looking for things to speed up, and I may find some more for you. > I'm also still waiting for an answer to the proposal for how to handle the > collections count issues on wtr-development. > Right. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060626/49311f19/attachment-0001.html From bret at pettichord.com Tue Jun 27 01:08:22 2006 From: bret at pettichord.com (Bret Pettichord) Date: Tue, 27 Jun 2006 00:08:22 -0500 Subject: [Wtr-development] Performance, Locators and the Strategy Pattern. Message-ID: David, I have two concerns about your recent changes. http://svn.openqa.org/fisheye/changelog/watir?cs=1049 http://svn.openqa.org/fisheye/changelog/watir?cs=1048 After more profiling I was seeing locate_input_element using over 60% of all > time during > one of my web scraper tests. Total time for the test was about 4 minutes, > with one minute > of that waiting for page loads. > > Most of my field lookups are by :id or :name so I checked for those > "how's" and instead > of iterating through all page elements I used the OLE getElementById and > getElementsByName > to find the element or collection. > > The performance difference is amazing. Before the 4 line change > locate_input_element took > 54.26% of the run time for my scrape. After this change it took 0.63%. > Run time went from > 3 minutes (ignoring page load times) down to about 1 minute (also ignoring > page load times). > > I'll keep looking for other ways to speed up Watir by using IE DHTML > methods to minimize > iterating through page elements one at a time. > > Previous patch had a problem with elements that didnt have getElementById > or getElementsByName. > This version fixes that by falling back to the previous method, but still > fails one unit test > where getElementByID returns an element with a matching name, but NO id. > I'll work tomorrow > on a fix for these conditions where the IE calls are "lying" 1. First of all, I'm unhappy seeing the addition of an unconstrained rescue block. I've been adding contstraints to the existing rescue blocks (i.e. specifying what error we trapping, rather than trapping all). We've had problems in the past with these kinds of rescue statements swallowing error messages. They really need to be used as a last resort at all, and when they are used, they should be should have the minimal scope (both lexically and in terms of the error trapped) as possible. 2. It's unclear to me how this performance enhancement coordinates with adding multiple attribute support. The multiple attribute support, at this time, is only attached to non-input elements and your performance improvement is attached to input elements, so there is not an immediate conflict. I'd appreciate if you gave this some thought. Ultimately, i think the need to trap errors was showing a flaw in the design -- namely the fact that your streamlined approach is not really put in the right place. The problem is that your alternates only for PageContainer#ole_inner_element and not for Element#ole_inner_element. The correct solution needs to use object-oriented design, rather than error trapping to ensure that the correct algorithm is used. Frankly these changes as well as the agreed need for a way to restrict locators to the immediate children of tables and rows point to the need for Locator classes along the line of what i've already done for non-input elements. Could you please take a look at TaggedElementLocator and think about how we can work together to develop this approach. The problem is that the locator algorithm depends on the type of element, the type of container and the type of attribute. And this is complicated more by the fact that the we are now supporting multiple attributes. With at least three dimensions, simple polymorphism isn't going to be enough to keep our code from being narly. If you read Design Patterns, TaggedElementLocator is an example of the Strategy Pattern. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060627/fa1e48a0/attachment.html From bret at pettichord.com Tue Jun 27 13:40:33 2006 From: bret at pettichord.com (Bret Pettichord) Date: Tue, 27 Jun 2006 12:40:33 -0500 Subject: [Wtr-development] Table Row Bug -- How to fix? In-Reply-To: <4490A323.8080502@tower-mt.com> References: <4490A323.8080502@tower-mt.com> Message-ID: It has taken me a long time to reply to David's suggestions. There are a number of issues here and i think we really need to try to separate them. First of all, there is the general issing of giving Watir the ability to navigate specifically to the child rows and cells of a table (or row). I think everyone agrees this would be a valuable addition to Watir. So there is the discussion of how to do this. Then there is the issue of whether we should change the existing behaviour. I have found, not always to my pleasure, that the Watir user community is very conservative. They don't like Watir to change. Mostly, i think this is understandable. For most, Watir is a tool that helps them manage change and they don't want it changing, too. One of the reasons i've been slow to officially release 1.5 is because once it is released, many of the API's are going to be very hard to change. I have a number of changes i want to make and a number of new features that i want to have time for feedback and the opportunity to change the interfaces before this resistance sets in. David, you should realize that your usage of Watir differs from the bulk of our users (because you use it for scraping rather than testing) and that your context forces you to ready to deal with unpredictable and unanticipated change. Testers need to be able to understand change (i.e. whether it represents a bug or not) whereas with scraping it's just something to you have to deal with. I said, nonetheless, that it was probably safe to change row_count to only count the rows that are children of the table. I say this because i think most testers are using this to verify that some table has the right number of rows, which represent some kind of object (e.g. items in an order) and ultimately they are unaware of the fact that this count could represent something else. In other words, this change is welcome because our users have perceived the existing behavior as a bug. On the other hand, changing the behavior of the row and cell and rows and cells methods will be harder to convince our users to accept. Or me. Let me explain a concrete example. I've build a library for my application that allows me to express scripts in terms of how we percieve our application's controls -- rather than how they are implemented in html. So we have buttons, but they are not html buttons, but rather compound objects consisting of a div containing a table that contains cells with links and images and text. In our library, button('foo') returns a watir object that can be clicked. I think currently it returns the link or the div, but it could just as well return a cell. We also have panels which contain different sections of a page. These panels have a box around them and are implemented as html tables. For us, panel('foo') returns the Watir::Table corresponding to the panel that has a title of 'foo' (actually the text in a cell of a particular class). We mostly use these when we have multiple controls with the same name on a page. So panel('foo').button('search') returns the button (really, say, a cell) in the panel (a table). But note that we are not looking for a cell that is a child of the panel table (which in this case it is not). This is just one example of where we have cell in a table, with no assumption that the cell is a child of the table. Making David's suggested change would break code like this. Of course it would be easy for me to update my library to use the new methods, if thought they were a good idea. But my point is really that i'm sure other users are also using cells in tables without care for whether they are children of the tables. It's a reasonable thing to do. I should point out that the way that Watir, first, allows users to easily access any element without concern for how deep it is in the hierachy has been key to its ease of use. And secondly, that our use of containers (forms, tables, divs) to restrict the scope of a search is a key usability feature (this is much more general in 1.5 than it was in 1.4). In other words, Watir flattens the html hierarchy, but allows users to make use of it when it is convenient. This flattening is a key aspect of Watir. Previously i've used testing tools that made it much harder to flatten the hierarchy, and did not provide the flexibilty to allow you to use it only when you needed it. I noticed that a Watij user recently reported a bug where the equivalent of link(:text, 'foo') did not work when 'foo' was not the value of the actual link element, but rather the value of a contained element. I don't think we've ever had a bug like this in Watir: the flattening concept has been with us from day one. At the same time, i acknowledge that many users have been confused when they learn that our commands for cells and rows are not restricted to actual children. This is why i think it would be good to add these as new commands (child_row, child_cell, child_rows and child_cells). If we were working from a clean slate, we could have a fair consideration over which behavior should attach the simpler names (row, cell). But in the existing case, we have to acknowledge reality, which is that there is a bias against changing the behavior of existing methods. David, even if i haven't convinced you that we need to keep the existing behavior, i must nonetheless insist that we table that issue until we have a concrete implementation of the new behavior. I made the mistake of not separating the issues of new functionality and changing default behavior in my recent proposal regarding wait_until. I suggest that we change Watir to automatically wait for an object to exist before allowing other methods to act on it, but there was a fair amount of confusing around exactly what i was proposing. That confusion was sufficient that even though i arguably got consensus for my proposal, i decided to treat that as void. What i should have done was focus on the new "wait_until" syntax and behavior, get that implemented and then use that concrete implementation going forward as the basis for making my proposal that we change the default behavior. And that in fact is how i plan to move ahead with that idea. (A half-built version of wait_until is in trunk.) So that means that we need to move forward with how to implement child_row, child_cell, child_rows, and child_cells. I'll take up that technical issue in a later email. (Although my short answer is: use the Strategy Pattern and create locator classes.) Bret On 6/14/06, David Schmidt wrote: > > Bret Pettichord wrote: > > Now for David's question. > > > > 1. I think that it is pretty safe to change row_count to only count > > the rows that belong to a table. I said this on wtr-general and there > > was no dissent and i think i was understood. > There may be a problem with just fixing row_count because of the way it > is used. In addition, there is a problem with *which* rows will be > retrieved even if the row_count is fixed to only show the row count for > each table and ignore rows in sub-tables. My understanding is that you are saying we could actually fix row_count, but there is also a separate, but related problem. Right? The problem comes into play when you go to retrieve the rows (and this > applies to any container for which there can be many sub-containers, > like cells or divs). For example, in our current unit tests we have > table1.html which contains a sub-table in one of the tables. > > I did a fix to the row_count and thought that things were fine when I > did the following test: > > t = ie.table(:index, 3) # the table which contains another > table > t.rows.length => 2 > t.rows.each {|r| puts r.html} > > That showed me the two rows in the parent table and I thought all was > good. So, I made the same type of changes for cells and spotted a > problem which affects rows too. The problem is that the elements > returned by .each (from getElementsByTagName()) are returned in the > order that they appear in the container element. For our table in > table1.html they would appear as row1 of table3, row2 of table3 and then > row1 of table4. When I only displayed the first two rows things looked > fine. > > However, table4 (the sub-table) is located in row2, cell1, so when I > used the same method to show cells for each row like this: > > t = ie.table(:index, 3) # the table which contains another > table > t.cells.length => 4 > t.cells.each {|c| puts c.html} > > Instead of getting the 4 cells from table 3, I got: > > cell 1 # row 1 cell 1 > > cell2 # row 1 cell 2 > > # row 2 cell 1, containing the entire sub-table > > >
nest1 > nest2
> > nest1 # OOPS!, this is row 1 cell 1 the sub-table, table4. > > This is because the cells are returned in the order that they are seen > in the HTML document, so the first cell of the sub-table (containing > "nest1") appears immediately after cell containing the sub-table. > > In order to get the correct items we need to use a different method > other than getElementsByTagName whenever we want *just* the directly > child elements. > > > 2. I originally thought that changing Watir so that ie.table(x).row(y) > > would only reference rows that belonged to the specified table would > > be safe, but as i've thought more about it and reflected on how i've > > used Watir, i think that there is a pretty good chance that changing > > this would break tests. In our DataCert application, we make commonly > > reference tables as generic scoping containers and cells as types of > > objects. We wrap the watir calls in an abstraction layer, so this > > isn't immediatly clear to a scripter. But if we made it so that calls > > to cell() would be restricted to child cells when the container was a > > table, then that would probably break things for us. > > > > David's suggestion to use different semantics based on attribute is > > not appealing to me. For one, because it simply is too difficult to > > expect average users to understand. And secondly, because it seems to > > break down if we consider the possibility of multiple attributes, > > which i've started to commit code for, and am using for table cells, > > among other objects. The idea of multiple attributes offers another > > possibility: another attribute that specifies whether we should > > restrict the collection to child elements. Maybe > > ie.table(x).row(:belongs_to => true, index => 1). But i think i have a > > better idea. > > > > A new method, ie.table(x).child_row(:index => 1). A child_row would be > > just like another Row, except it would use a different locator method. > > > > Anyway, that is my proposal. It would mean adding child_row and > > child_cell to the Table and Row classes. It wouldn't break any tests. > > And i think that it would be pretty easy to understand. Only certain > > objects would have these methods, so it would be easy to tell (via the > > rdocs) which elements supported them. > > > > Regardless, of the interface, let me move to discussing how to > > implement them. > > > > This week i created a new Locator class (TaggedElementLocator) and i > > expect to be refactoring the code to create more. I've long thought > > that the locator methods, currently in the container class, really > > belonged in the element classes -- because it is the class of the > > element that determines what locator method is use. By creating > > separate classes for them, this ultimately facilitates this move. The > > urgent motivation for this change was that i needed to implement > > multiple attribute selection. But i also had this issue in mind as i > > worked on it. > > > > I think the right solution now mainly amounts to creating a > > ChildRowLocator and ChildCellLocator subclasses, refactoring > > TaggedElementLocator to isolate the call that now appears as the first > > line of locate and then create new ChildRow and ChildCell subclasses > > of Row and Cell, with modified locate methods. Since the child_row and > > child_cell factory methods (a factory method is a method that creates > > an object -- the def_creator class method that is used to create most > > of these factory methods is not a factory method, but rather a factory > > method factory, if you want to call it that) would only be defined for > > containers that make sense (Table, Row), there is no need to check the > > class of the container. In other words, not only is this approach > > pretty easy for users to comprehend, it is also fairly > > straight-forward to implement. > > > > > > However, the > > getElementsByTagName method is called from many different places > > within > > Watir, > > > > This is a code smell. One source of this duplication is the many > > show_* methods. Most could be replaced with simple calls to > > Collection#show. E.g. show_rows could be replace with rows.show (and > > child_rows.show). > > > > and one of the places is Container#locate_tagged_element, which > > uses getElementsByTagName for many different tag types. > > > > This is the call that is now delegated to the new Locator class. > > > > The problem > > > > with this is that while the same method is used to get ALL tags of a > > given type, each DOM element has it's own *specfic* method to > > return the > > collection of specific child nodes (like "rows" for table rows, > > "cells" > > for table cells, etc). > > > > > > Right. So you need to change the locate method of ChildRows and > > ChildCells to use your new locators instead. (Just instantiate and > > call them directly in the element locate method -- there is no reason > > to include the container in the delegation chain. > > > > How does this sound? > First, a couple of notes about the implementation above. This problem > will occur in any container that can contain another of it's own kind as > a sub-container. Unfortunately, while the getElementsByTagName is the > method used by all the containers to retrieve ALL tags below the current > point, the method used to get just the child elements has a different > name for different containers, like "rows" for a table's direct rows, > and "cells" for a tables direct cells. > > My first test implementation to fix the problem used the "children" > method, which should be available from each container. One problem with > writing a "generic" getChildElements is that rows and cells are NOT > direct descendants of tables. Rows may be contained in THEAD, TFOOT or > TBODY elements, and cells may be contained > (http://www.w3.org/TR/html4/struct/tables.html). > > This means you have to put in special code to find all rows for a given > table, or all cells for a given row because the rows will be children of > a table child: > > irb(main):078:0> t.document.children.each {|child| puts child.tagName} > TBODY > > irb(main):079:0> t.document.children['0'].children.each {|child| puts > child.tagName} > TR > TR > > Even the DOM can be inconsistent at times. For example, check out all > of the collections at > > http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/collections.asp > . > Some return ALL items in the document, others return all children below > a container and some return only direct descendants of a container. The > "cells" collection is even more interesting. If called from a table > element it will return all cells in the current table, but if called > from a row it will return just cells in that row (ignoring cells in > sub-tables in either case). > > So, no matter what we decide to do, there will be a bunch of special > code to handle special cases. Bleah. > > Second, I would like to see our methods match, as closely as possible, > the DOM methods. This would imply that our "rows" method will return > just the rows for the current table, and will ignore sub-tables. > Obviously, this *will* break current tests. So, how about another way > to do this which will maintain current functionality while adding new > functionality and yet giving the users a choice of how they want the > current commands to work. > > My suggestion is this. We implement Bret's suggestion above as > getChildElementsByTag, using the current Watir method names with > "child_" prepended. I.E., "table().child_rows", "table().child_cells", > etc. > > We also implement method names to explicitly show the current > functionality by prepending "all_" to each current method. I.E., > "table().all_rows" or "table().all_cells" which would *by default* work > just like "table().rows" and "table().cells". > > Lastly, we create a configuration variable which will allow testers to > *change* which methods the old names use, with the default to be set to > leave them as they are now. For example, "table().rows" would give ALL > rows below a table, even rows in sub-tables unless (for example) the > tester set @@collection_retrieval_style to "child", in which case > "table().rows" would return only the rows in that table. > > "Row_count" (and "cell_count") would also have additional methods like > "all_row_count" and "child_row_count" and the default would be the > current "all_" method. > > We could then recommend that tests be coded to use the more explicit > method names, and someday we could possibly change the default if we > wanted, but for now all current tests would run as-is, but people > desiring the "new" behavior could turn it on if they wanted, and people > needing *both* behaviors would have ways to make that clear in their > scripts by using "all_" or "child_" for all the methods. > > I'd recommend that we document *both* styles in a table which would show > the equivalent DOM methods to make it clear what elements will be > returned by each of the four methods ("all_", "child_", > default(current), optional(by setting an option)). > > Current unit tests would run as they do now, but we could add unit tests > for the "all_" or "child_" versions along with tests which would test > the behaviors of the old commands with the configuration switched. > > I'll volunteer to do the implementation and can probably have some trial > versions ready in a day or two. > > David > _______________________________________________ > Wtr-development mailing list > Wtr-development at rubyforge.org > http://rubyforge.org/mailman/listinfo/wtr-development > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060627/39b2dc5d/attachment-0001.html From bret at pettichord.com Tue Jun 27 13:42:06 2006 From: bret at pettichord.com (Bret Pettichord) Date: Tue, 27 Jun 2006 12:42:06 -0500 Subject: [Wtr-development] Fwd: [Wtr-general] very neat trick with Ruby system() (or any otherlanguage on Windows) In-Reply-To: References: <4491DDC9.1040206@tower-mt.com> Message-ID: David, I did not see a response to my question below. Bret ---------- Forwarded message ---------- From: Bret Pettichord Date: Jun 16, 2006 1:53 PM Subject: Re: [Wtr-general] very neat trick with Ruby system() (or any otherlanguage on Windows) To: wtr-general at rubyforge.org On 6/15/06, David Schmidt wrote: > Bret, > > The current method is quite a bit different than the method that I > wrote, and I'm not sure it will be as flexible. (For example, you can't > attach to a Frame the way you can to an IE or Modal window.) My method > is designed to completely re-create the exact method string to get back > to the element to be clicked, and is working well for me right now, > though there are some inconsistencies with table related elements (which > is what got me looking at our current container/collection issue). Right. The method in trunk handles click_no_wait in all watir objects except frames. It is impervious to how we've implemented support for most controls and therefore is unaffected by the issues you've raised with table elements. To my thinking, that makes this code more flexible than what is in the modal_dialog branch. We just need to add support for frames. It's probably just two lines of code. I guess i can do it if you are uncomfortable with this approach. It's at https://svn.openqa.org/svn/watir/branches/modal_dialog/watir and > I'm doing lots of click_no_wait's from within frames. Feel free to > contact me if you have questions about the code in that branch as it's > pretty much my branch right now and it's probably a dead end until it's > decided to port that code to the current trunk. What do we have in there that isn't already in trunk, other than the frame/click_no_wait support? Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/wtr-development/attachments/20060627/a8c8e021/attachment.html From davids at tower-mt.com Thu Jun 1 16:23:14 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 01 Jun 2006 13:23:14 -0700 Subject: [Wtr-development] [Wtr-general] Determine HTML property In-Reply-To: References: Message-ID: <447F4CB2.6070902@tower-mt.com> Zeljko Filipin wrote: > ie.radio(:id, "id").readonly? > > On 6/1/06, *Adrian Rutter* > wrote: > > > Hi, > > I have an HTML field that once saved becomes read-only > [readonly="true"]. > Apart from doing a regex on the source how can I determine this > property? > > Cheers > > Aidy > I've just encountered a situation where this doesn't work, and written a fix for it, though I'm not sure where this fix would best be integrated. The problem is that while an input element may NOT be read only, a containing element like a table cell, table row or div may have their visibility turned off, which prevents Watir from setting the focus on the input element and effectively makes the input element read only even though the readonly attribute is false: irb(main):014:0> ie.text_field(:id, 'Detail_Date').readonly? => false irb(main):015:0> ie.text_field(:id, 'Detail_Date').set('01/01/2000') WIN32OLERuntimeError: focus OLE error code:800A083E in htmlfile Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus. HRESULT error code:0x80020009 Exception occurred. from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `method_missing' from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `set' from (irb):15 In this case, a TR element a few levels higher has a style of "visibility: hidden; display: none" so the control is invisible and thus read only. I see a few solutions. The first would be to try to update the input element and then rescue the WIN32OLERuntimeError exception. I'm not particularly fond of this, especially since the exception isn't an exception specific to this problem. Another option is to iterate up the DOM elements checking every element to make sure that is is visible. This could be done in Element#readonly?, but then we wouldn't be able to see the value of the actual readonly attribute. I chose to implement another method which I called "writable?" which first checks that the element exists, is enabled and not readonly and then moves up the DOM tree and reports false if any element is not visible (visibility != 'hidden' and display != 'none'). I've tested this and while it can be slow if the input element is deeply embedded it *does* seem to be accurate: irb(main):016:0> ie.text_field(:id, 'Detail_Date').writable? => false irb(main):017:0> ie.text_field(:id, 'Detail_DOB').writable? => true You can try this by adding the following method in your Watir script or by adding just the writable? definition inside class Element in Watir.rb. I can add this to trunk once I get some tests written to test it if we decide this is the way to go. Does anyone have a cleaner or faster way to do this? module Watir class Element # Determine if we can write to a DOM element. # If any parent element isn't visible then we cannot write to the # element. The only realiable way to determine this is to iterate # up the DOM elemint tree checking every element to make sure it's # visible. def writable? assert_exists # First make sure the element itself is writable begin assert_enabled assert_not_readonly rescue Watir::Exception::ObjectDisabledException, Watir::Exception::ObjectReadOnlyException return false end return false if ! document.iscontentEditable # Now iterate up the DOM element tree and return false if any # parent element isn't visible or is disabled. object = document while object begin if object.style.invoke('visibility') =~ /^hidden$/i return false end if object.style.invoke('display') =~ /^none$/i return false end if object.invoke('isDisabled') return false end rescue WIN32OLERuntimeError end object += '.parentElement' end true end end end From davids at tower-mt.com Thu Jun 1 16:23:14 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 01 Jun 2006 13:23:14 -0700 Subject: [Wtr-development] [Wtr-general] Determine HTML property In-Reply-To: References: Message-ID: <447F4CB2.6070902@tower-mt.com> Zeljko Filipin wrote: > ie.radio(:id, "id").readonly? > > On 6/1/06, *Adrian Rutter* > wrote: > > > Hi, > > I have an HTML field that once saved becomes read-only > [readonly="true"]. > Apart from doing a regex on the source how can I determine this > property? > > Cheers > > Aidy > I've just encountered a situation where this doesn't work, and written a fix for it, though I'm not sure where this fix would best be integrated. The problem is that while an input element may NOT be read only, a containing element like a table cell, table row or div may have their visibility turned off, which prevents Watir from setting the focus on the input element and effectively makes the input element read only even though the readonly attribute is false: irb(main):014:0> ie.text_field(:id, 'Detail_Date').readonly? => false irb(main):015:0> ie.text_field(:id, 'Detail_Date').set('01/01/2000') WIN32OLERuntimeError: focus OLE error code:800A083E in htmlfile Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus. HRESULT error code:0x80020009 Exception occurred. from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `method_missing' from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `set' from (irb):15 In this case, a TR element a few levels higher has a style of "visibility: hidden; display: none" so the control is invisible and thus read only. I see a few solutions. The first would be to try to update the input element and then rescue the WIN32OLERuntimeError exception. I'm not particularly fond of this, especially since the exception isn't an exception specific to this problem. Another option is to iterate up the DOM elements checking every element to make sure that is is visible. This could be done in Element#readonly?, but then we wouldn't be able to see the value of the actual readonly attribute. I chose to implement another method which I called "writable?" which first checks that the element exists, is enabled and not readonly and then moves up the DOM tree and reports false if any element is not visible (visibility != 'hidden' and display != 'none'). I've tested this and while it can be slow if the input element is deeply embedded it *does* seem to be accurate: irb(main):016:0> ie.text_field(:id, 'Detail_Date').writable? => false irb(main):017:0> ie.text_field(:id, 'Detail_DOB').writable? => true You can try this by adding the following method in your Watir script or by adding just the writable? definition inside class Element in Watir.rb. I can add this to trunk once I get some tests written to test it if we decide this is the way to go. Does anyone have a cleaner or faster way to do this? module Watir class Element # Determine if we can write to a DOM element. # If any parent element isn't visible then we cannot write to the # element. The only realiable way to determine this is to iterate # up the DOM elemint tree checking every element to make sure it's # visible. def writable? assert_exists # First make sure the element itself is writable begin assert_enabled assert_not_readonly rescue Watir::Exception::ObjectDisabledException, Watir::Exception::ObjectReadOnlyException return false end return false if ! document.iscontentEditable # Now iterate up the DOM element tree and return false if any # parent element isn't visible or is disabled. object = document while object begin if object.style.invoke('visibility') =~ /^hidden$/i return false end if object.style.invoke('display') =~ /^none$/i return false end if object.invoke('isDisabled') return false end rescue WIN32OLERuntimeError end object += '.parentElement' end true end end end From davids at tower-mt.com Thu Jun 1 16:23:14 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 01 Jun 2006 13:23:14 -0700 Subject: [Wtr-development] [Wtr-general] Determine HTML property In-Reply-To: References: Message-ID: <447F4CB2.6070902@tower-mt.com> Zeljko Filipin wrote: > ie.radio(:id, "id").readonly? > > On 6/1/06, *Adrian Rutter* > wrote: > > > Hi, > > I have an HTML field that once saved becomes read-only > [readonly="true"]. > Apart from doing a regex on the source how can I determine this > property? > > Cheers > > Aidy > I've just encountered a situation where this doesn't work, and written a fix for it, though I'm not sure where this fix would best be integrated. The problem is that while an input element may NOT be read only, a containing element like a table cell, table row or div may have their visibility turned off, which prevents Watir from setting the focus on the input element and effectively makes the input element read only even though the readonly attribute is false: irb(main):014:0> ie.text_field(:id, 'Detail_Date').readonly? => false irb(main):015:0> ie.text_field(:id, 'Detail_Date').set('01/01/2000') WIN32OLERuntimeError: focus OLE error code:800A083E in htmlfile Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus. HRESULT error code:0x80020009 Exception occurred. from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `method_missing' from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `set' from (irb):15 In this case, a TR element a few levels higher has a style of "visibility: hidden; display: none" so the control is invisible and thus read only. I see a few solutions. The first would be to try to update the input element and then rescue the WIN32OLERuntimeError exception. I'm not particularly fond of this, especially since the exception isn't an exception specific to this problem. Another option is to iterate up the DOM elements checking every element to make sure that is is visible. This could be done in Element#readonly?, but then we wouldn't be able to see the value of the actual readonly attribute. I chose to implement another method which I called "writable?" which first checks that the element exists, is enabled and not readonly and then moves up the DOM tree and reports false if any element is not visible (visibility != 'hidden' and display != 'none'). I've tested this and while it can be slow if the input element is deeply embedded it *does* seem to be accurate: irb(main):016:0> ie.text_field(:id, 'Detail_Date').writable? => false irb(main):017:0> ie.text_field(:id, 'Detail_DOB').writable? => true You can try this by adding the following method in your Watir script or by adding just the writable? definition inside class Element in Watir.rb. I can add this to trunk once I get some tests written to test it if we decide this is the way to go. Does anyone have a cleaner or faster way to do this? module Watir class Element # Determine if we can write to a DOM element. # If any parent element isn't visible then we cannot write to the # element. The only realiable way to determine this is to iterate # up the DOM elemint tree checking every element to make sure it's # visible. def writable? assert_exists # First make sure the element itself is writable begin assert_enabled assert_not_readonly rescue Watir::Exception::ObjectDisabledException, Watir::Exception::ObjectReadOnlyException return false end return false if ! document.iscontentEditable # Now iterate up the DOM element tree and return false if any # parent element isn't visible or is disabled. object = document while object begin if object.style.invoke('visibility') =~ /^hidden$/i return false end if object.style.invoke('display') =~ /^none$/i return false end if object.invoke('isDisabled') return false end rescue WIN32OLERuntimeError end object += '.parentElement' end true end end end From davids at tower-mt.com Thu Jun 1 16:23:14 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 01 Jun 2006 13:23:14 -0700 Subject: [Wtr-development] [Wtr-general] Determine HTML property In-Reply-To: References: Message-ID: <447F4CB2.6070902@tower-mt.com> Zeljko Filipin wrote: > ie.radio(:id, "id").readonly? > > On 6/1/06, *Adrian Rutter* > wrote: > > > Hi, > > I have an HTML field that once saved becomes read-only > [readonly="true"]. > Apart from doing a regex on the source how can I determine this > property? > > Cheers > > Aidy > I've just encountered a situation where this doesn't work, and written a fix for it, though I'm not sure where this fix would best be integrated. The problem is that while an input element may NOT be read only, a containing element like a table cell, table row or div may have their visibility turned off, which prevents Watir from setting the focus on the input element and effectively makes the input element read only even though the readonly attribute is false: irb(main):014:0> ie.text_field(:id, 'Detail_Date').readonly? => false irb(main):015:0> ie.text_field(:id, 'Detail_Date').set('01/01/2000') WIN32OLERuntimeError: focus OLE error code:800A083E in htmlfile Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus. HRESULT error code:0x80020009 Exception occurred. from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `method_missing' from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `set' from (irb):15 In this case, a TR element a few levels higher has a style of "visibility: hidden; display: none" so the control is invisible and thus read only. I see a few solutions. The first would be to try to update the input element and then rescue the WIN32OLERuntimeError exception. I'm not particularly fond of this, especially since the exception isn't an exception specific to this problem. Another option is to iterate up the DOM elements checking every element to make sure that is is visible. This could be done in Element#readonly?, but then we wouldn't be able to see the value of the actual readonly attribute. I chose to implement another method which I called "writable?" which first checks that the element exists, is enabled and not readonly and then moves up the DOM tree and reports false if any element is not visible (visibility != 'hidden' and display != 'none'). I've tested this and while it can be slow if the input element is deeply embedded it *does* seem to be accurate: irb(main):016:0> ie.text_field(:id, 'Detail_Date').writable? => false irb(main):017:0> ie.text_field(:id, 'Detail_DOB').writable? => true You can try this by adding the following method in your Watir script or by adding just the writable? definition inside class Element in Watir.rb. I can add this to trunk once I get some tests written to test it if we decide this is the way to go. Does anyone have a cleaner or faster way to do this? module Watir class Element # Determine if we can write to a DOM element. # If any parent element isn't visible then we cannot write to the # element. The only realiable way to determine this is to iterate # up the DOM elemint tree checking every element to make sure it's # visible. def writable? assert_exists # First make sure the element itself is writable begin assert_enabled assert_not_readonly rescue Watir::Exception::ObjectDisabledException, Watir::Exception::ObjectReadOnlyException return false end return false if ! document.iscontentEditable # Now iterate up the DOM element tree and return false if any # parent element isn't visible or is disabled. object = document while object begin if object.style.invoke('visibility') =~ /^hidden$/i return false end if object.style.invoke('display') =~ /^none$/i return false end if object.invoke('isDisabled') return false end rescue WIN32OLERuntimeError end object += '.parentElement' end true end end end From davids at tower-mt.com Thu Jun 1 16:23:14 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 01 Jun 2006 13:23:14 -0700 Subject: [Wtr-development] [Wtr-general] Determine HTML property In-Reply-To: References: Message-ID: <447F4CB2.6070902@tower-mt.com> Zeljko Filipin wrote: > ie.radio(:id, "id").readonly? > > On 6/1/06, *Adrian Rutter* > wrote: > > > Hi, > > I have an HTML field that once saved becomes read-only > [readonly="true"]. > Apart from doing a regex on the source how can I determine this > property? > > Cheers > > Aidy > I've just encountered a situation where this doesn't work, and written a fix for it, though I'm not sure where this fix would best be integrated. The problem is that while an input element may NOT be read only, a containing element like a table cell, table row or div may have their visibility turned off, which prevents Watir from setting the focus on the input element and effectively makes the input element read only even though the readonly attribute is false: irb(main):014:0> ie.text_field(:id, 'Detail_Date').readonly? => false irb(main):015:0> ie.text_field(:id, 'Detail_Date').set('01/01/2000') WIN32OLERuntimeError: focus OLE error code:800A083E in htmlfile Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus. HRESULT error code:0x80020009 Exception occurred. from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `method_missing' from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `set' from (irb):15 In this case, a TR element a few levels higher has a style of "visibility: hidden; display: none" so the control is invisible and thus read only. I see a few solutions. The first would be to try to update the input element and then rescue the WIN32OLERuntimeError exception. I'm not particularly fond of this, especially since the exception isn't an exception specific to this problem. Another option is to iterate up the DOM elements checking every element to make sure that is is visible. This could be done in Element#readonly?, but then we wouldn't be able to see the value of the actual readonly attribute. I chose to implement another method which I called "writable?" which first checks that the element exists, is enabled and not readonly and then moves up the DOM tree and reports false if any element is not visible (visibility != 'hidden' and display != 'none'). I've tested this and while it can be slow if the input element is deeply embedded it *does* seem to be accurate: irb(main):016:0> ie.text_field(:id, 'Detail_Date').writable? => false irb(main):017:0> ie.text_field(:id, 'Detail_DOB').writable? => true You can try this by adding the following method in your Watir script or by adding just the writable? definition inside class Element in Watir.rb. I can add this to trunk once I get some tests written to test it if we decide this is the way to go. Does anyone have a cleaner or faster way to do this? module Watir class Element # Determine if we can write to a DOM element. # If any parent element isn't visible then we cannot write to the # element. The only realiable way to determine this is to iterate # up the DOM elemint tree checking every element to make sure it's # visible. def writable? assert_exists # First make sure the element itself is writable begin assert_enabled assert_not_readonly rescue Watir::Exception::ObjectDisabledException, Watir::Exception::ObjectReadOnlyException return false end return false if ! document.iscontentEditable # Now iterate up the DOM element tree and return false if any # parent element isn't visible or is disabled. object = document while object begin if object.style.invoke('visibility') =~ /^hidden$/i return false end if object.style.invoke('display') =~ /^none$/i return false end if object.invoke('isDisabled') return false end rescue WIN32OLERuntimeError end object += '.parentElement' end true end end end From jared at kilmore.info Wed Jun 7 02:00:40 2006 From: jared at kilmore.info (Jared Quinert) Date: Wed, 07 Jun 2006 16:00:40 +1000 Subject: [Wtr-development] [Wtr-general] Watir 1.5.x Performance Issues? In-Reply-To: <4485EBA8.8040907@titanez.net> References: <4485EBA8.8040907@titanez.net> Message-ID: <44866B88.5010502@kilmore.info> Hi Bret, When you mentioned timeouts, were you referring to this line in watir.rb - DEFAULT_SLEEP_TIME = ...or to changes in the wait method? Or is it something else? I had a quick look/grep through the 1.5 source but wasn't sure. Jared >> >> I spend a lot of time tuning my test suites to make them run fast, >> without running so fast that they become unreliable. Typically, this >> involves tuning timeouts (which are in 1.5, but not in 1.4) and >> removing sleeps. Of course, i always run Watir in "fast mode". >> >> Bret > > ------------------------------------------------------------------------ > > _______________________________________________ > Wtr-general mailing list > Wtr-general at rubyforge.org > http://rubyforge.org/mailman/listinfo/wtr-general -------------- next part -------------- An HTML attachment was scrubbed... URL: From davids at tower-mt.com Sat Jun 10 20:56:46 2006 From: davids at tower-mt.com (David Schmidt) Date: Sat, 10 Jun 2006 17:56:46 -0700 Subject: [Wtr-development] Table Row Bug -- How to fix? Message-ID: <448B6A4E.9080009@tower-mt.com> Hi all, I've been working on the Table Row bug, and I have some questions about what changes folks want. The bottom line issue is *when* to apply the fix. (Note that this applies to any DOM collection, not just table rows.) I now have code which can accurately count just the rows in the current table instead of all rows below a certain point in the DOM. Same thing with cells. However the code to retrieve a row or cell by :index also needs to be adjusted, but I'm not certain how best to do this. This is because there are two ways to look for rows. Watir allows you to find a row anywhere in the document like "ie.row(:index, 3)" or "ie.row(:id, 'xx')". The other way would be below a table or table-group ("THEAD", "TFOOT" or "TBODY") as in "ie.table(:how, what).row(:index, x)" or "ie.table(:how, what)[n]". Here's my question. Under which conditions should the selection of rows be restricted to just those in the current table, and when should the selection be for all rows below the current object? If we change which rows are selected using any methods we risk breaking existing scripts, but I would argue that certain methods should only consider rows in the current table. My current opinion is that when selecting a row by :index (or via []) we would restrict the selection to just those rows in the current table and ignore any rows in any sub-tables. When selecting by :id or :name it may still be appropriate to select all rows below the current element. I'd like to see some consensus before changing something that could affect existing scripts, but I do think there are times to restrict the selection to just the current table. David Schmidt From bret at pettichord.com Wed Jun 14 15:32:44 2006 From: bret at pettichord.com (Bret Pettichord) Date: Wed, 14 Jun 2006 14:32:44 -0500 Subject: [Wtr-development] timeouts Message-ID: > > Hi Bret, > > When you mentioned timeouts, were you referring to this line in watir.rb > - > > DEFAULT_SLEEP_TIME = > > ...or to changes in the wait method? > > Or is it something else? I had a quick look/grep through the 1.5 source > but wasn't sure. > > Jared > > I was referring to @@attach_timeout. My application makes common use of modal dialogs, which is affected by this. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Wed Jun 14 17:06:19 2006 From: bret at pettichord.com (Bret Pettichord) Date: Wed, 14 Jun 2006 16:06:19 -0500 Subject: [Wtr-development] Table Row Bug -- How to fix? Message-ID: > > Hi all, I've been working on the Table Row bug, and I have some > questions about what changes folks want. The bottom line issue is > > *when* to apply the fix. (Note that this applies to any DOM collection, > not just table rows.) > > I now have code which can accurately count just the rows in the current > table instead of all rows below a certain point in the DOM. Same thing > > with cells. However the code to retrieve a row or cell by :index also > needs to be adjusted, but I'm not certain how best to do this. This is > because there are two ways to look for rows. Watir allows you to find a > > row anywhere in the document like "ie.row(:index, 3)" or "ie.row(:id, > 'xx')". The other way would be below a table or table-group ("THEAD", > "TFOOT" or "TBODY") as in " > ie.table(:how, what).row(:index, x)" or > "ie.table(:how, what)[n]". > > Here's my question. Under which conditions should the selection of rows > be restricted to just those in the current table, and when should the > > selection be for all rows below the current object? If we change which > rows are selected using any methods we risk breaking existing scripts, > but I would argue that certain methods should only consider rows in the > > current table. > > My current opinion is that when selecting a row by :index (or via []) we > > would restrict the selection to just those rows in the current table and > ignore any rows in any sub-tables. When selecting by :id or :name it > may still be appropriate to select all rows below the current element. > > > I'd like to see some consensus before changing something that could > affect existing scripts, but I do think there are times to restrict the > selection to just the current table. > > David Schmidt > > Before i get to David's specific question, let me make a couple of comments. 1. My apologies for the delay in responding. Next time I need to remember to subscribe to a new list when i create it. 2. The purpose of this list is to discuss the how of developing Watir. In other words, how to we make particular changes? What unit tests do we need? I've been finding the need to discuss the architecture of Watir and what i like and dislike about it and that kind of conversation doesn't really belong on wtr-general where we have people who still don't understand how to use assertions. 3. This isn't a good place to get approval for changes that will break existing user tests. Wtr-general is the place for that. But it may be a good place to get feedback on an idea before presenting it to that forum. Personally, i am trying to involve the community more in Watir design discussions and this has been a personal challenge. Now for David's question. 1. I think that it is pretty safe to change row_count to only count the rows that belong to a table. I said this on wtr-general and there was no dissent and i think i was understood. 2. I originally thought that changing Watir so that ie.table(x).row(y) would only reference rows that belonged to the specified table would be safe, but as i've thought more about it and reflected on how i've used Watir, i think that there is a pretty good chance that changing this would break tests. In our DataCert application, we make commonly reference tables as generic scoping containers and cells as types of objects. We wrap the watir calls in an abstraction layer, so this isn't immediatly clear to a scripter. But if we made it so that calls to cell() would be restricted to child cells when the container was a table, then that would probably break things for us. David's suggestion to use different semantics based on attribute is not appealing to me. For one, because it simply is too difficult to expect average users to understand. And secondly, because it seems to break down if we consider the possibility of multiple attributes, which i've started to commit code for, and am using for table cells, among other objects. The idea of multiple attributes offers another possibility: another attribute that specifies whether we should restrict the collection to child elements. Maybe ie.table(x).row(:belongs_to => true, index => 1). But i think i have a better idea. A new method, ie.table(x).child_row(:index => 1). A child_row would be just like another Row, except it would use a different locator method. Anyway, that is my proposal. It would mean adding child_row and child_cell to the Table and Row classes. It wouldn't break any tests. And i think that it would be pretty easy to understand. Only certain objects would have these methods, so it would be easy to tell (via the rdocs) which elements supported them. Regardless, of the interface, let me move to discussing how to implement them. This week i created a new Locator class (TaggedElementLocator) and i expect to be refactoring the code to create more. I've long thought that the locator methods, currently in the container class, really belonged in the element classes -- because it is the class of the element that determines what locator method is use. By creating separate classes for them, this ultimately facilitates this move. The urgent motivation for this change was that i needed to implement multiple attribute selection. But i also had this issue in mind as i worked on it. I think the right solution now mainly amounts to creating a ChildRowLocator and ChildCellLocator subclasses, refactoring TaggedElementLocator to isolate the call that now appears as the first line of locate and then create new ChildRow and ChildCell subclasses of Row and Cell, with modified locate methods. Since the child_row and child_cell factory methods (a factory method is a method that creates an object -- the def_creator class method that is used to create most of these factory methods is not a factory method, but rather a factory method factory, if you want to call it that) would only be defined for containers that make sense (Table, Row), there is no need to check the class of the container. In other words, not only is this approach pretty easy for users to comprehend, it is also fairly straight-forward to implement. However, the getElementsByTagName method is called from many different places within Watir, This is a code smell. One source of this duplication is the many show_* methods. Most could be replaced with simple calls to Collection#show. E.g. show_rows could be replace with rows.show (and child_rows.show). and one of the places is Container#locate_tagged_element, which uses getElementsByTagName for many different tag types. This is the call that is now delegated to the new Locator class. The problem > with this is that while the same method is used to get ALL tags of a > given type, each DOM element has it's own *specfic* method to return the > collection of specific child nodes (like "rows" for table rows, "cells" > for table cells, etc). > Right. So you need to change the locate method of ChildRows and ChildCells to use your new locators instead. (Just instantiate and call them directly in the element locate method -- there is no reason to include the container in the delegation chain. How does this sound? -------------- next part -------------- An HTML attachment was scrubbed... URL: From davids at tower-mt.com Wed Jun 14 20:00:35 2006 From: davids at tower-mt.com (David Schmidt) Date: Wed, 14 Jun 2006 17:00:35 -0700 Subject: [Wtr-development] Table Row Bug -- How to fix? In-Reply-To: References: Message-ID: <4490A323.8080502@tower-mt.com> Bret Pettichord wrote: > Now for David's question. > > 1. I think that it is pretty safe to change row_count to only count > the rows that belong to a table. I said this on wtr-general and there > was no dissent and i think i was understood. There may be a problem with just fixing row_count because of the way it is used. In addition, there is a problem with *which* rows will be retrieved even if the row_count is fixed to only show the row count for each table and ignore rows in sub-tables. The problem comes into play when you go to retrieve the rows (and this applies to any container for which there can be many sub-containers, like cells or divs). For example, in our current unit tests we have table1.html which contains a sub-table in one of the tables. I did a fix to the row_count and thought that things were fine when I did the following test: t = ie.table(:index, 3) # the table which contains another table t.rows.length => 2 t.rows.each {|r| puts r.html} That showed me the two rows in the parent table and I thought all was good. So, I made the same type of changes for cells and spotted a problem which affects rows too. The problem is that the elements returned by .each (from getElementsByTagName()) are returned in the order that they appear in the container element. For our table in table1.html they would appear as row1 of table3, row2 of table3 and then row1 of table4. When I only displayed the first two rows things looked fine. However, table4 (the sub-table) is located in row2, cell1, so when I used the same method to show cells for each row like this: t = ie.table(:index, 3) # the table which contains another table t.cells.length => 4 t.cells.each {|c| puts c.html} Instead of getting the 4 cells from table 3, I got: cell 1 # row 1 cell 1 cell2 # row 1 cell 2 # row 2 cell 1, containing the entire sub-table
nest1 nest2
nest1 # OOPS!, this is row 1 cell 1 the sub-table, table4. This is because the cells are returned in the order that they are seen in the HTML document, so the first cell of the sub-table (containing "nest1") appears immediately after cell containing the sub-table. In order to get the correct items we need to use a different method other than getElementsByTagName whenever we want *just* the directly child elements. > 2. I originally thought that changing Watir so that ie.table(x).row(y) > would only reference rows that belonged to the specified table would > be safe, but as i've thought more about it and reflected on how i've > used Watir, i think that there is a pretty good chance that changing > this would break tests. In our DataCert application, we make commonly > reference tables as generic scoping containers and cells as types of > objects. We wrap the watir calls in an abstraction layer, so this > isn't immediatly clear to a scripter. But if we made it so that calls > to cell() would be restricted to child cells when the container was a > table, then that would probably break things for us. > > David's suggestion to use different semantics based on attribute is > not appealing to me. For one, because it simply is too difficult to > expect average users to understand. And secondly, because it seems to > break down if we consider the possibility of multiple attributes, > which i've started to commit code for, and am using for table cells, > among other objects. The idea of multiple attributes offers another > possibility: another attribute that specifies whether we should > restrict the collection to child elements. Maybe > ie.table(x).row(:belongs_to => true, index => 1). But i think i have a > better idea. > > A new method, ie.table(x).child_row(:index => 1). A child_row would be > just like another Row, except it would use a different locator method. > > Anyway, that is my proposal. It would mean adding child_row and > child_cell to the Table and Row classes. It wouldn't break any tests. > And i think that it would be pretty easy to understand. Only certain > objects would have these methods, so it would be easy to tell (via the > rdocs) which elements supported them. > > Regardless, of the interface, let me move to discussing how to > implement them. > > This week i created a new Locator class (TaggedElementLocator) and i > expect to be refactoring the code to create more. I've long thought > that the locator methods, currently in the container class, really > belonged in the element classes -- because it is the class of the > element that determines what locator method is use. By creating > separate classes for them, this ultimately facilitates this move. The > urgent motivation for this change was that i needed to implement > multiple attribute selection. But i also had this issue in mind as i > worked on it. > > I think the right solution now mainly amounts to creating a > ChildRowLocator and ChildCellLocator subclasses, refactoring > TaggedElementLocator to isolate the call that now appears as the first > line of locate and then create new ChildRow and ChildCell subclasses > of Row and Cell, with modified locate methods. Since the child_row and > child_cell factory methods (a factory method is a method that creates > an object -- the def_creator class method that is used to create most > of these factory methods is not a factory method, but rather a factory > method factory, if you want to call it that) would only be defined for > containers that make sense (Table, Row), there is no need to check the > class of the container. In other words, not only is this approach > pretty easy for users to comprehend, it is also fairly > straight-forward to implement. > > > However, the > getElementsByTagName method is called from many different places > within > Watir, > > This is a code smell. One source of this duplication is the many > show_* methods. Most could be replaced with simple calls to > Collection#show. E.g. show_rows could be replace with rows.show (and > child_rows.show). > > and one of the places is Container#locate_tagged_element, which > uses getElementsByTagName for many different tag types. > > This is the call that is now delegated to the new Locator class. > > The problem > > with this is that while the same method is used to get ALL tags of a > given type, each DOM element has it's own *specfic* method to > return the > collection of specific child nodes (like "rows" for table rows, > "cells" > for table cells, etc). > > > Right. So you need to change the locate method of ChildRows and > ChildCells to use your new locators instead. (Just instantiate and > call them directly in the element locate method -- there is no reason > to include the container in the delegation chain. > > How does this sound? First, a couple of notes about the implementation above. This problem will occur in any container that can contain another of it's own kind as a sub-container. Unfortunately, while the getElementsByTagName is the method used by all the containers to retrieve ALL tags below the current point, the method used to get just the child elements has a different name for different containers, like "rows" for a table's direct rows, and "cells" for a tables direct cells. My first test implementation to fix the problem used the "children" method, which should be available from each container. One problem with writing a "generic" getChildElements is that rows and cells are NOT direct descendants of tables. Rows may be contained in THEAD, TFOOT or TBODY elements, and cells may be contained (http://www.w3.org/TR/html4/struct/tables.html). This means you have to put in special code to find all rows for a given table, or all cells for a given row because the rows will be children of a table child: irb(main):078:0> t.document.children.each {|child| puts child.tagName} TBODY irb(main):079:0> t.document.children['0'].children.each {|child| puts child.tagName} TR TR Even the DOM can be inconsistent at times. For example, check out all of the collections at http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/collections.asp. Some return ALL items in the document, others return all children below a container and some return only direct descendants of a container. The "cells" collection is even more interesting. If called from a table element it will return all cells in the current table, but if called from a row it will return just cells in that row (ignoring cells in sub-tables in either case). So, no matter what we decide to do, there will be a bunch of special code to handle special cases. Bleah. Second, I would like to see our methods match, as closely as possible, the DOM methods. This would imply that our "rows" method will return just the rows for the current table, and will ignore sub-tables. Obviously, this *will* break current tests. So, how about another way to do this which will maintain current functionality while adding new functionality and yet giving the users a choice of how they want the current commands to work. My suggestion is this. We implement Bret's suggestion above as getChildElementsByTag, using the current Watir method names with "child_" prepended. I.E., "table().child_rows", "table().child_cells", etc. We also implement method names to explicitly show the current functionality by prepending "all_" to each current method. I.E., "table().all_rows" or "table().all_cells" which would *by default* work just like "table().rows" and "table().cells". Lastly, we create a configuration variable which will allow testers to *change* which methods the old names use, with the default to be set to leave them as they are now. For example, "table().rows" would give ALL rows below a table, even rows in sub-tables unless (for example) the tester set @@collection_retrieval_style to "child", in which case "table().rows" would return only the rows in that table. "Row_count" (and "cell_count") would also have additional methods like "all_row_count" and "child_row_count" and the default would be the current "all_" method. We could then recommend that tests be coded to use the more explicit method names, and someday we could possibly change the default if we wanted, but for now all current tests would run as-is, but people desiring the "new" behavior could turn it on if they wanted, and people needing *both* behaviors would have ways to make that clear in their scripts by using "all_" or "child_" for all the methods. I'd recommend that we document *both* styles in a table which would show the equivalent DOM methods to make it clear what elements will be returned by each of the four methods ("all_", "child_", default(current), optional(by setting an option)). Current unit tests would run as they do now, but we could add unit tests for the "all_" or "child_" versions along with tests which would test the behaviors of the old commands with the configuration switched. I'll volunteer to do the implementation and can probably have some trial versions ready in a day or two. David From bret at pettichord.com Thu Jun 22 14:01:07 2006 From: bret at pettichord.com (Bret Pettichord) Date: Thu, 22 Jun 2006 13:01:07 -0500 Subject: [Wtr-development] Performance Improvement Message-ID: David, Thanks for the recent performance improvement http://svn.openqa.org/fisheye/changelog/watir?cs=1046 You may be interested to know that in Ruby 1.6, if you returned from within a WIN32OLE.each block, you got a LocalJumpError. That's why the pre-existing code was so inefficient. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Fri Jun 23 11:33:10 2006 From: bret at pettichord.com (Bret Pettichord) Date: Fri, 23 Jun 2006 10:33:10 -0500 Subject: [Wtr-development] Performance Improvement In-Reply-To: References: Message-ID: I have another followup comment. 1046 created by > inetdavid on 22 June 2006, 02:39:36 -0500 (31 hours ago) (patch) > After profiling a web scraper that was running much slower with 1.5.1 than > with 1.4.1 > I found that 69% of the time was spent in locate_input_element(), almost > all of that time > in WIN32OLE#each. I saw that the each loop was continuing to run even > after an object > was found, so I re-wrote the loop so that the routine returns a value as > soon as one > is found and now that routine is only using 57% of CPU on the same test. > One problem with profiling is that it ignores the #1 cause of delay with Watir scripts -- sleeps. In general, i've made suites perform better by tweaking polling loops and reducing the time spent sleeping. But sleep-time is not counted as CPU time by the profiler, so it is effectively ignored. In other words, profiling makes code more efficient, but not necessarily faster. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: From davids at tower-mt.com Thu Jun 22 20:53:46 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 22 Jun 2006 17:53:46 -0700 Subject: [Wtr-development] Performance Improvement In-Reply-To: References: Message-ID: <449B3B9A.1080008@tower-mt.com> Even with that restriction, the "next" should have been a "break" to break out of the each loop as soon as a match was found. With the "next" the process looped over all values, even after a match was found. Glad to help though. We're seeing things running much slower under 1.5.1 so we're looking for things to speed up, and I may find some more for you. I'm also still waiting for an answer to the proposal for how to handle the collections count issues on wtr-development. David Bret Pettichord wrote: > David, > > Thanks for the recent performance improvement > > http://svn.openqa.org/fisheye/changelog/watir?cs=1046 > > You may be interested to know that in Ruby 1.6, if you returned from > within a WIN32OLE.each block, you got a LocalJumpError. That's why the > pre-existing code was so inefficient. > > Bret > ------------------------------------------------------------------------ > > _______________________________________________ > Wtr-development mailing list > Wtr-development at rubyforge.org > http://rubyforge.org/mailman/listinfo/wtr-development -------------- next part -------------- An HTML attachment was scrubbed... URL: From davids at tower-mt.com Mon Jun 26 18:57:45 2006 From: davids at tower-mt.com (David Schmidt) Date: Mon, 26 Jun 2006 15:57:45 -0700 Subject: [Wtr-development] Performance Improvement In-Reply-To: References: Message-ID: <44A06669.3030805@tower-mt.com> Bret Pettichord wrote: > I have another followup comment. > > 1046 > created by inetdavid on 22 June 2006, 02:39:36 -0500 (31 hours > ago) (patch > ) > > After profiling a web scraper that was running much slower with > 1.5.1 than with 1.4.1 > I found that 69% of the time was spent in locate_input_element(), > almost all of that time > in WIN32OLE#each. I saw that the each loop was continuing to run > even after an object > was found, so I re-wrote the loop so that the routine returns a > value as soon as one > is found and now that routine is only using 57% of CPU on the same > test. > > > One problem with profiling is that it ignores the #1 cause of delay > with Watir scripts -- sleeps. > > In general, i've made suites perform better by tweaking polling loops > and reducing the time spent sleeping. But sleep-time is not counted as > CPU time by the profiler, so it is effectively ignored. > > In other words, profiling makes code more efficient, but not > necessarily faster. > > Bret I'm using the latest ruby-prof gem (version 1.4.1) and it does account for time spent in Kernel#sleep. Watir::IE#wait was the biggest caller of sleep (as expected) with #until_with_timeout being the second biggest as I'm using it to watch AJAX "spinners" until they disappear before I fill the following field. My timers account for both of those with code that starts a timer before every click and then stops after a page (or AJAX update) is finished loading. Using WIN32OLE#each is a performance killer because OLE calls are relatively expensive. I doubled the speed of my scraper's screen filling with this change because almost all elements are located using :id or :name, and this patch lets Watir locate an :id object in one call, and a :name collection in one call plus one call for every element with that name. Only hassle is that getElementById will return an element that happens to have a matching name attribute, which may be what most people *want* to happen, but isn't entirely accurate and will break tests where there are two elements of the same type where one has an id attribute and the other has a name attribute that matches. David David From bret at pettichord.com Mon Jun 26 19:35:09 2006 From: bret at pettichord.com (Bret Pettichord) Date: Mon, 26 Jun 2006 18:35:09 -0500 Subject: [Wtr-development] Performance Improvement In-Reply-To: <449B3B9A.1080008@tower-mt.com> References: <449B3B9A.1080008@tower-mt.com> Message-ID: On 6/22/06, David Schmidt wrote: > > Even with that restriction, the "next" should have been a "break" to > break out of the each loop as soon as a match was found. With the "next" > the process looped over all values, even after a match was found. > A break inside the each block would also caused a LocalJumpError in Ruby 1.6 . > Glad to help though. We're seeing things running much slower under 1.5.1so we're looking for things to speed up, and I may find some more for you. > I'm also still waiting for an answer to the proposal for how to handle the > collections count issues on wtr-development. > Right. -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Tue Jun 27 01:08:22 2006 From: bret at pettichord.com (Bret Pettichord) Date: Tue, 27 Jun 2006 00:08:22 -0500 Subject: [Wtr-development] Performance, Locators and the Strategy Pattern. Message-ID: David, I have two concerns about your recent changes. http://svn.openqa.org/fisheye/changelog/watir?cs=1049 http://svn.openqa.org/fisheye/changelog/watir?cs=1048 After more profiling I was seeing locate_input_element using over 60% of all > time during > one of my web scraper tests. Total time for the test was about 4 minutes, > with one minute > of that waiting for page loads. > > Most of my field lookups are by :id or :name so I checked for those > "how's" and instead > of iterating through all page elements I used the OLE getElementById and > getElementsByName > to find the element or collection. > > The performance difference is amazing. Before the 4 line change > locate_input_element took > 54.26% of the run time for my scrape. After this change it took 0.63%. > Run time went from > 3 minutes (ignoring page load times) down to about 1 minute (also ignoring > page load times). > > I'll keep looking for other ways to speed up Watir by using IE DHTML > methods to minimize > iterating through page elements one at a time. > > Previous patch had a problem with elements that didnt have getElementById > or getElementsByName. > This version fixes that by falling back to the previous method, but still > fails one unit test > where getElementByID returns an element with a matching name, but NO id. > I'll work tomorrow > on a fix for these conditions where the IE calls are "lying" 1. First of all, I'm unhappy seeing the addition of an unconstrained rescue block. I've been adding contstraints to the existing rescue blocks (i.e. specifying what error we trapping, rather than trapping all). We've had problems in the past with these kinds of rescue statements swallowing error messages. They really need to be used as a last resort at all, and when they are used, they should be should have the minimal scope (both lexically and in terms of the error trapped) as possible. 2. It's unclear to me how this performance enhancement coordinates with adding multiple attribute support. The multiple attribute support, at this time, is only attached to non-input elements and your performance improvement is attached to input elements, so there is not an immediate conflict. I'd appreciate if you gave this some thought. Ultimately, i think the need to trap errors was showing a flaw in the design -- namely the fact that your streamlined approach is not really put in the right place. The problem is that your alternates only for PageContainer#ole_inner_element and not for Element#ole_inner_element. The correct solution needs to use object-oriented design, rather than error trapping to ensure that the correct algorithm is used. Frankly these changes as well as the agreed need for a way to restrict locators to the immediate children of tables and rows point to the need for Locator classes along the line of what i've already done for non-input elements. Could you please take a look at TaggedElementLocator and think about how we can work together to develop this approach. The problem is that the locator algorithm depends on the type of element, the type of container and the type of attribute. And this is complicated more by the fact that the we are now supporting multiple attributes. With at least three dimensions, simple polymorphism isn't going to be enough to keep our code from being narly. If you read Design Patterns, TaggedElementLocator is an example of the Strategy Pattern. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Tue Jun 27 13:40:33 2006 From: bret at pettichord.com (Bret Pettichord) Date: Tue, 27 Jun 2006 12:40:33 -0500 Subject: [Wtr-development] Table Row Bug -- How to fix? In-Reply-To: <4490A323.8080502@tower-mt.com> References: <4490A323.8080502@tower-mt.com> Message-ID: It has taken me a long time to reply to David's suggestions. There are a number of issues here and i think we really need to try to separate them. First of all, there is the general issing of giving Watir the ability to navigate specifically to the child rows and cells of a table (or row). I think everyone agrees this would be a valuable addition to Watir. So there is the discussion of how to do this. Then there is the issue of whether we should change the existing behaviour. I have found, not always to my pleasure, that the Watir user community is very conservative. They don't like Watir to change. Mostly, i think this is understandable. For most, Watir is a tool that helps them manage change and they don't want it changing, too. One of the reasons i've been slow to officially release 1.5 is because once it is released, many of the API's are going to be very hard to change. I have a number of changes i want to make and a number of new features that i want to have time for feedback and the opportunity to change the interfaces before this resistance sets in. David, you should realize that your usage of Watir differs from the bulk of our users (because you use it for scraping rather than testing) and that your context forces you to ready to deal with unpredictable and unanticipated change. Testers need to be able to understand change (i.e. whether it represents a bug or not) whereas with scraping it's just something to you have to deal with. I said, nonetheless, that it was probably safe to change row_count to only count the rows that are children of the table. I say this because i think most testers are using this to verify that some table has the right number of rows, which represent some kind of object (e.g. items in an order) and ultimately they are unaware of the fact that this count could represent something else. In other words, this change is welcome because our users have perceived the existing behavior as a bug. On the other hand, changing the behavior of the row and cell and rows and cells methods will be harder to convince our users to accept. Or me. Let me explain a concrete example. I've build a library for my application that allows me to express scripts in terms of how we percieve our application's controls -- rather than how they are implemented in html. So we have buttons, but they are not html buttons, but rather compound objects consisting of a div containing a table that contains cells with links and images and text. In our library, button('foo') returns a watir object that can be clicked. I think currently it returns the link or the div, but it could just as well return a cell. We also have panels which contain different sections of a page. These panels have a box around them and are implemented as html tables. For us, panel('foo') returns the Watir::Table corresponding to the panel that has a title of 'foo' (actually the text in a cell of a particular class). We mostly use these when we have multiple controls with the same name on a page. So panel('foo').button('search') returns the button (really, say, a cell) in the panel (a table). But note that we are not looking for a cell that is a child of the panel table (which in this case it is not). This is just one example of where we have cell in a table, with no assumption that the cell is a child of the table. Making David's suggested change would break code like this. Of course it would be easy for me to update my library to use the new methods, if thought they were a good idea. But my point is really that i'm sure other users are also using cells in tables without care for whether they are children of the tables. It's a reasonable thing to do. I should point out that the way that Watir, first, allows users to easily access any element without concern for how deep it is in the hierachy has been key to its ease of use. And secondly, that our use of containers (forms, tables, divs) to restrict the scope of a search is a key usability feature (this is much more general in 1.5 than it was in 1.4). In other words, Watir flattens the html hierarchy, but allows users to make use of it when it is convenient. This flattening is a key aspect of Watir. Previously i've used testing tools that made it much harder to flatten the hierarchy, and did not provide the flexibilty to allow you to use it only when you needed it. I noticed that a Watij user recently reported a bug where the equivalent of link(:text, 'foo') did not work when 'foo' was not the value of the actual link element, but rather the value of a contained element. I don't think we've ever had a bug like this in Watir: the flattening concept has been with us from day one. At the same time, i acknowledge that many users have been confused when they learn that our commands for cells and rows are not restricted to actual children. This is why i think it would be good to add these as new commands (child_row, child_cell, child_rows and child_cells). If we were working from a clean slate, we could have a fair consideration over which behavior should attach the simpler names (row, cell). But in the existing case, we have to acknowledge reality, which is that there is a bias against changing the behavior of existing methods. David, even if i haven't convinced you that we need to keep the existing behavior, i must nonetheless insist that we table that issue until we have a concrete implementation of the new behavior. I made the mistake of not separating the issues of new functionality and changing default behavior in my recent proposal regarding wait_until. I suggest that we change Watir to automatically wait for an object to exist before allowing other methods to act on it, but there was a fair amount of confusing around exactly what i was proposing. That confusion was sufficient that even though i arguably got consensus for my proposal, i decided to treat that as void. What i should have done was focus on the new "wait_until" syntax and behavior, get that implemented and then use that concrete implementation going forward as the basis for making my proposal that we change the default behavior. And that in fact is how i plan to move ahead with that idea. (A half-built version of wait_until is in trunk.) So that means that we need to move forward with how to implement child_row, child_cell, child_rows, and child_cells. I'll take up that technical issue in a later email. (Although my short answer is: use the Strategy Pattern and create locator classes.) Bret On 6/14/06, David Schmidt wrote: > > Bret Pettichord wrote: > > Now for David's question. > > > > 1. I think that it is pretty safe to change row_count to only count > > the rows that belong to a table. I said this on wtr-general and there > > was no dissent and i think i was understood. > There may be a problem with just fixing row_count because of the way it > is used. In addition, there is a problem with *which* rows will be > retrieved even if the row_count is fixed to only show the row count for > each table and ignore rows in sub-tables. My understanding is that you are saying we could actually fix row_count, but there is also a separate, but related problem. Right? The problem comes into play when you go to retrieve the rows (and this > applies to any container for which there can be many sub-containers, > like cells or divs). For example, in our current unit tests we have > table1.html which contains a sub-table in one of the tables. > > I did a fix to the row_count and thought that things were fine when I > did the following test: > > t = ie.table(:index, 3) # the table which contains another > table > t.rows.length => 2 > t.rows.each {|r| puts r.html} > > That showed me the two rows in the parent table and I thought all was > good. So, I made the same type of changes for cells and spotted a > problem which affects rows too. The problem is that the elements > returned by .each (from getElementsByTagName()) are returned in the > order that they appear in the container element. For our table in > table1.html they would appear as row1 of table3, row2 of table3 and then > row1 of table4. When I only displayed the first two rows things looked > fine. > > However, table4 (the sub-table) is located in row2, cell1, so when I > used the same method to show cells for each row like this: > > t = ie.table(:index, 3) # the table which contains another > table > t.cells.length => 4 > t.cells.each {|c| puts c.html} > > Instead of getting the 4 cells from table 3, I got: > > cell 1 # row 1 cell 1 > > cell2 # row 1 cell 2 > > # row 2 cell 1, containing the entire sub-table > > >
nest1 > nest2
> > nest1 # OOPS!, this is row 1 cell 1 the sub-table, table4. > > This is because the cells are returned in the order that they are seen > in the HTML document, so the first cell of the sub-table (containing > "nest1") appears immediately after cell containing the sub-table. > > In order to get the correct items we need to use a different method > other than getElementsByTagName whenever we want *just* the directly > child elements. > > > 2. I originally thought that changing Watir so that ie.table(x).row(y) > > would only reference rows that belonged to the specified table would > > be safe, but as i've thought more about it and reflected on how i've > > used Watir, i think that there is a pretty good chance that changing > > this would break tests. In our DataCert application, we make commonly > > reference tables as generic scoping containers and cells as types of > > objects. We wrap the watir calls in an abstraction layer, so this > > isn't immediatly clear to a scripter. But if we made it so that calls > > to cell() would be restricted to child cells when the container was a > > table, then that would probably break things for us. > > > > David's suggestion to use different semantics based on attribute is > > not appealing to me. For one, because it simply is too difficult to > > expect average users to understand. And secondly, because it seems to > > break down if we consider the possibility of multiple attributes, > > which i've started to commit code for, and am using for table cells, > > among other objects. The idea of multiple attributes offers another > > possibility: another attribute that specifies whether we should > > restrict the collection to child elements. Maybe > > ie.table(x).row(:belongs_to => true, index => 1). But i think i have a > > better idea. > > > > A new method, ie.table(x).child_row(:index => 1). A child_row would be > > just like another Row, except it would use a different locator method. > > > > Anyway, that is my proposal. It would mean adding child_row and > > child_cell to the Table and Row classes. It wouldn't break any tests. > > And i think that it would be pretty easy to understand. Only certain > > objects would have these methods, so it would be easy to tell (via the > > rdocs) which elements supported them. > > > > Regardless, of the interface, let me move to discussing how to > > implement them. > > > > This week i created a new Locator class (TaggedElementLocator) and i > > expect to be refactoring the code to create more. I've long thought > > that the locator methods, currently in the container class, really > > belonged in the element classes -- because it is the class of the > > element that determines what locator method is use. By creating > > separate classes for them, this ultimately facilitates this move. The > > urgent motivation for this change was that i needed to implement > > multiple attribute selection. But i also had this issue in mind as i > > worked on it. > > > > I think the right solution now mainly amounts to creating a > > ChildRowLocator and ChildCellLocator subclasses, refactoring > > TaggedElementLocator to isolate the call that now appears as the first > > line of locate and then create new ChildRow and ChildCell subclasses > > of Row and Cell, with modified locate methods. Since the child_row and > > child_cell factory methods (a factory method is a method that creates > > an object -- the def_creator class method that is used to create most > > of these factory methods is not a factory method, but rather a factory > > method factory, if you want to call it that) would only be defined for > > containers that make sense (Table, Row), there is no need to check the > > class of the container. In other words, not only is this approach > > pretty easy for users to comprehend, it is also fairly > > straight-forward to implement. > > > > > > However, the > > getElementsByTagName method is called from many different places > > within > > Watir, > > > > This is a code smell. One source of this duplication is the many > > show_* methods. Most could be replaced with simple calls to > > Collection#show. E.g. show_rows could be replace with rows.show (and > > child_rows.show). > > > > and one of the places is Container#locate_tagged_element, which > > uses getElementsByTagName for many different tag types. > > > > This is the call that is now delegated to the new Locator class. > > > > The problem > > > > with this is that while the same method is used to get ALL tags of a > > given type, each DOM element has it's own *specfic* method to > > return the > > collection of specific child nodes (like "rows" for table rows, > > "cells" > > for table cells, etc). > > > > > > Right. So you need to change the locate method of ChildRows and > > ChildCells to use your new locators instead. (Just instantiate and > > call them directly in the element locate method -- there is no reason > > to include the container in the delegation chain. > > > > How does this sound? > First, a couple of notes about the implementation above. This problem > will occur in any container that can contain another of it's own kind as > a sub-container. Unfortunately, while the getElementsByTagName is the > method used by all the containers to retrieve ALL tags below the current > point, the method used to get just the child elements has a different > name for different containers, like "rows" for a table's direct rows, > and "cells" for a tables direct cells. > > My first test implementation to fix the problem used the "children" > method, which should be available from each container. One problem with > writing a "generic" getChildElements is that rows and cells are NOT > direct descendants of tables. Rows may be contained in THEAD, TFOOT or > TBODY elements, and cells may be contained > (http://www.w3.org/TR/html4/struct/tables.html). > > This means you have to put in special code to find all rows for a given > table, or all cells for a given row because the rows will be children of > a table child: > > irb(main):078:0> t.document.children.each {|child| puts child.tagName} > TBODY > > irb(main):079:0> t.document.children['0'].children.each {|child| puts > child.tagName} > TR > TR > > Even the DOM can be inconsistent at times. For example, check out all > of the collections at > > http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/collections.asp > . > Some return ALL items in the document, others return all children below > a container and some return only direct descendants of a container. The > "cells" collection is even more interesting. If called from a table > element it will return all cells in the current table, but if called > from a row it will return just cells in that row (ignoring cells in > sub-tables in either case). > > So, no matter what we decide to do, there will be a bunch of special > code to handle special cases. Bleah. > > Second, I would like to see our methods match, as closely as possible, > the DOM methods. This would imply that our "rows" method will return > just the rows for the current table, and will ignore sub-tables. > Obviously, this *will* break current tests. So, how about another way > to do this which will maintain current functionality while adding new > functionality and yet giving the users a choice of how they want the > current commands to work. > > My suggestion is this. We implement Bret's suggestion above as > getChildElementsByTag, using the current Watir method names with > "child_" prepended. I.E., "table().child_rows", "table().child_cells", > etc. > > We also implement method names to explicitly show the current > functionality by prepending "all_" to each current method. I.E., > "table().all_rows" or "table().all_cells" which would *by default* work > just like "table().rows" and "table().cells". > > Lastly, we create a configuration variable which will allow testers to > *change* which methods the old names use, with the default to be set to > leave them as they are now. For example, "table().rows" would give ALL > rows below a table, even rows in sub-tables unless (for example) the > tester set @@collection_retrieval_style to "child", in which case > "table().rows" would return only the rows in that table. > > "Row_count" (and "cell_count") would also have additional methods like > "all_row_count" and "child_row_count" and the default would be the > current "all_" method. > > We could then recommend that tests be coded to use the more explicit > method names, and someday we could possibly change the default if we > wanted, but for now all current tests would run as-is, but people > desiring the "new" behavior could turn it on if they wanted, and people > needing *both* behaviors would have ways to make that clear in their > scripts by using "all_" or "child_" for all the methods. > > I'd recommend that we document *both* styles in a table which would show > the equivalent DOM methods to make it clear what elements will be > returned by each of the four methods ("all_", "child_", > default(current), optional(by setting an option)). > > Current unit tests would run as they do now, but we could add unit tests > for the "all_" or "child_" versions along with tests which would test > the behaviors of the old commands with the configuration switched. > > I'll volunteer to do the implementation and can probably have some trial > versions ready in a day or two. > > David > _______________________________________________ > Wtr-development mailing list > Wtr-development at rubyforge.org > http://rubyforge.org/mailman/listinfo/wtr-development > -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Tue Jun 27 13:42:06 2006 From: bret at pettichord.com (Bret Pettichord) Date: Tue, 27 Jun 2006 12:42:06 -0500 Subject: [Wtr-development] Fwd: [Wtr-general] very neat trick with Ruby system() (or any otherlanguage on Windows) In-Reply-To: References: <4491DDC9.1040206@tower-mt.com> Message-ID: David, I did not see a response to my question below. Bret ---------- Forwarded message ---------- From: Bret Pettichord Date: Jun 16, 2006 1:53 PM Subject: Re: [Wtr-general] very neat trick with Ruby system() (or any otherlanguage on Windows) To: wtr-general at rubyforge.org On 6/15/06, David Schmidt wrote: > Bret, > > The current method is quite a bit different than the method that I > wrote, and I'm not sure it will be as flexible. (For example, you can't > attach to a Frame the way you can to an IE or Modal window.) My method > is designed to completely re-create the exact method string to get back > to the element to be clicked, and is working well for me right now, > though there are some inconsistencies with table related elements (which > is what got me looking at our current container/collection issue). Right. The method in trunk handles click_no_wait in all watir objects except frames. It is impervious to how we've implemented support for most controls and therefore is unaffected by the issues you've raised with table elements. To my thinking, that makes this code more flexible than what is in the modal_dialog branch. We just need to add support for frames. It's probably just two lines of code. I guess i can do it if you are uncomfortable with this approach. It's at https://svn.openqa.org/svn/watir/branches/modal_dialog/watir and > I'm doing lots of click_no_wait's from within frames. Feel free to > contact me if you have questions about the code in that branch as it's > pretty much my branch right now and it's probably a dead end until it's > decided to port that code to the current trunk. What do we have in there that isn't already in trunk, other than the frame/click_no_wait support? Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: From davids at tower-mt.com Thu Jun 1 16:23:14 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 01 Jun 2006 13:23:14 -0700 Subject: [Wtr-development] [Wtr-general] Determine HTML property In-Reply-To: References: Message-ID: <447F4CB2.6070902@tower-mt.com> Zeljko Filipin wrote: > ie.radio(:id, "id").readonly? > > On 6/1/06, *Adrian Rutter* > wrote: > > > Hi, > > I have an HTML field that once saved becomes read-only > [readonly="true"]. > Apart from doing a regex on the source how can I determine this > property? > > Cheers > > Aidy > I've just encountered a situation where this doesn't work, and written a fix for it, though I'm not sure where this fix would best be integrated. The problem is that while an input element may NOT be read only, a containing element like a table cell, table row or div may have their visibility turned off, which prevents Watir from setting the focus on the input element and effectively makes the input element read only even though the readonly attribute is false: irb(main):014:0> ie.text_field(:id, 'Detail_Date').readonly? => false irb(main):015:0> ie.text_field(:id, 'Detail_Date').set('01/01/2000') WIN32OLERuntimeError: focus OLE error code:800A083E in htmlfile Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus. HRESULT error code:0x80020009 Exception occurred. from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `method_missing' from c:/ruby/lib/ruby/gems/1.8/gems/watir-1.5.0.1010/./watir.rb:3871:in `set' from (irb):15 In this case, a TR element a few levels higher has a style of "visibility: hidden; display: none" so the control is invisible and thus read only. I see a few solutions. The first would be to try to update the input element and then rescue the WIN32OLERuntimeError exception. I'm not particularly fond of this, especially since the exception isn't an exception specific to this problem. Another option is to iterate up the DOM elements checking every element to make sure that is is visible. This could be done in Element#readonly?, but then we wouldn't be able to see the value of the actual readonly attribute. I chose to implement another method which I called "writable?" which first checks that the element exists, is enabled and not readonly and then moves up the DOM tree and reports false if any element is not visible (visibility != 'hidden' and display != 'none'). I've tested this and while it can be slow if the input element is deeply embedded it *does* seem to be accurate: irb(main):016:0> ie.text_field(:id, 'Detail_Date').writable? => false irb(main):017:0> ie.text_field(:id, 'Detail_DOB').writable? => true You can try this by adding the following method in your Watir script or by adding just the writable? definition inside class Element in Watir.rb. I can add this to trunk once I get some tests written to test it if we decide this is the way to go. Does anyone have a cleaner or faster way to do this? module Watir class Element # Determine if we can write to a DOM element. # If any parent element isn't visible then we cannot write to the # element. The only realiable way to determine this is to iterate # up the DOM elemint tree checking every element to make sure it's # visible. def writable? assert_exists # First make sure the element itself is writable begin assert_enabled assert_not_readonly rescue Watir::Exception::ObjectDisabledException, Watir::Exception::ObjectReadOnlyException return false end return false if ! document.iscontentEditable # Now iterate up the DOM element tree and return false if any # parent element isn't visible or is disabled. object = document while object begin if object.style.invoke('visibility') =~ /^hidden$/i return false end if object.style.invoke('display') =~ /^none$/i return false end if object.invoke('isDisabled') return false end rescue WIN32OLERuntimeError end object += '.parentElement' end true end end end From jared at kilmore.info Wed Jun 7 02:00:40 2006 From: jared at kilmore.info (Jared Quinert) Date: Wed, 07 Jun 2006 16:00:40 +1000 Subject: [Wtr-development] [Wtr-general] Watir 1.5.x Performance Issues? In-Reply-To: <4485EBA8.8040907@titanez.net> References: <4485EBA8.8040907@titanez.net> Message-ID: <44866B88.5010502@kilmore.info> Hi Bret, When you mentioned timeouts, were you referring to this line in watir.rb - DEFAULT_SLEEP_TIME = ...or to changes in the wait method? Or is it something else? I had a quick look/grep through the 1.5 source but wasn't sure. Jared >> >> I spend a lot of time tuning my test suites to make them run fast, >> without running so fast that they become unreliable. Typically, this >> involves tuning timeouts (which are in 1.5, but not in 1.4) and >> removing sleeps. Of course, i always run Watir in "fast mode". >> >> Bret > > ------------------------------------------------------------------------ > > _______________________________________________ > Wtr-general mailing list > Wtr-general at rubyforge.org > http://rubyforge.org/mailman/listinfo/wtr-general -------------- next part -------------- An HTML attachment was scrubbed... URL: From davids at tower-mt.com Sat Jun 10 20:56:46 2006 From: davids at tower-mt.com (David Schmidt) Date: Sat, 10 Jun 2006 17:56:46 -0700 Subject: [Wtr-development] Table Row Bug -- How to fix? Message-ID: <448B6A4E.9080009@tower-mt.com> Hi all, I've been working on the Table Row bug, and I have some questions about what changes folks want. The bottom line issue is *when* to apply the fix. (Note that this applies to any DOM collection, not just table rows.) I now have code which can accurately count just the rows in the current table instead of all rows below a certain point in the DOM. Same thing with cells. However the code to retrieve a row or cell by :index also needs to be adjusted, but I'm not certain how best to do this. This is because there are two ways to look for rows. Watir allows you to find a row anywhere in the document like "ie.row(:index, 3)" or "ie.row(:id, 'xx')". The other way would be below a table or table-group ("THEAD", "TFOOT" or "TBODY") as in "ie.table(:how, what).row(:index, x)" or "ie.table(:how, what)[n]". Here's my question. Under which conditions should the selection of rows be restricted to just those in the current table, and when should the selection be for all rows below the current object? If we change which rows are selected using any methods we risk breaking existing scripts, but I would argue that certain methods should only consider rows in the current table. My current opinion is that when selecting a row by :index (or via []) we would restrict the selection to just those rows in the current table and ignore any rows in any sub-tables. When selecting by :id or :name it may still be appropriate to select all rows below the current element. I'd like to see some consensus before changing something that could affect existing scripts, but I do think there are times to restrict the selection to just the current table. David Schmidt From bret at pettichord.com Wed Jun 14 15:32:44 2006 From: bret at pettichord.com (Bret Pettichord) Date: Wed, 14 Jun 2006 14:32:44 -0500 Subject: [Wtr-development] timeouts Message-ID: > > Hi Bret, > > When you mentioned timeouts, were you referring to this line in watir.rb > - > > DEFAULT_SLEEP_TIME = > > ...or to changes in the wait method? > > Or is it something else? I had a quick look/grep through the 1.5 source > but wasn't sure. > > Jared > > I was referring to @@attach_timeout. My application makes common use of modal dialogs, which is affected by this. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Wed Jun 14 17:06:19 2006 From: bret at pettichord.com (Bret Pettichord) Date: Wed, 14 Jun 2006 16:06:19 -0500 Subject: [Wtr-development] Table Row Bug -- How to fix? Message-ID: > > Hi all, I've been working on the Table Row bug, and I have some > questions about what changes folks want. The bottom line issue is > > *when* to apply the fix. (Note that this applies to any DOM collection, > not just table rows.) > > I now have code which can accurately count just the rows in the current > table instead of all rows below a certain point in the DOM. Same thing > > with cells. However the code to retrieve a row or cell by :index also > needs to be adjusted, but I'm not certain how best to do this. This is > because there are two ways to look for rows. Watir allows you to find a > > row anywhere in the document like "ie.row(:index, 3)" or "ie.row(:id, > 'xx')". The other way would be below a table or table-group ("THEAD", > "TFOOT" or "TBODY") as in " > ie.table(:how, what).row(:index, x)" or > "ie.table(:how, what)[n]". > > Here's my question. Under which conditions should the selection of rows > be restricted to just those in the current table, and when should the > > selection be for all rows below the current object? If we change which > rows are selected using any methods we risk breaking existing scripts, > but I would argue that certain methods should only consider rows in the > > current table. > > My current opinion is that when selecting a row by :index (or via []) we > > would restrict the selection to just those rows in the current table and > ignore any rows in any sub-tables. When selecting by :id or :name it > may still be appropriate to select all rows below the current element. > > > I'd like to see some consensus before changing something that could > affect existing scripts, but I do think there are times to restrict the > selection to just the current table. > > David Schmidt > > Before i get to David's specific question, let me make a couple of comments. 1. My apologies for the delay in responding. Next time I need to remember to subscribe to a new list when i create it. 2. The purpose of this list is to discuss the how of developing Watir. In other words, how to we make particular changes? What unit tests do we need? I've been finding the need to discuss the architecture of Watir and what i like and dislike about it and that kind of conversation doesn't really belong on wtr-general where we have people who still don't understand how to use assertions. 3. This isn't a good place to get approval for changes that will break existing user tests. Wtr-general is the place for that. But it may be a good place to get feedback on an idea before presenting it to that forum. Personally, i am trying to involve the community more in Watir design discussions and this has been a personal challenge. Now for David's question. 1. I think that it is pretty safe to change row_count to only count the rows that belong to a table. I said this on wtr-general and there was no dissent and i think i was understood. 2. I originally thought that changing Watir so that ie.table(x).row(y) would only reference rows that belonged to the specified table would be safe, but as i've thought more about it and reflected on how i've used Watir, i think that there is a pretty good chance that changing this would break tests. In our DataCert application, we make commonly reference tables as generic scoping containers and cells as types of objects. We wrap the watir calls in an abstraction layer, so this isn't immediatly clear to a scripter. But if we made it so that calls to cell() would be restricted to child cells when the container was a table, then that would probably break things for us. David's suggestion to use different semantics based on attribute is not appealing to me. For one, because it simply is too difficult to expect average users to understand. And secondly, because it seems to break down if we consider the possibility of multiple attributes, which i've started to commit code for, and am using for table cells, among other objects. The idea of multiple attributes offers another possibility: another attribute that specifies whether we should restrict the collection to child elements. Maybe ie.table(x).row(:belongs_to => true, index => 1). But i think i have a better idea. A new method, ie.table(x).child_row(:index => 1). A child_row would be just like another Row, except it would use a different locator method. Anyway, that is my proposal. It would mean adding child_row and child_cell to the Table and Row classes. It wouldn't break any tests. And i think that it would be pretty easy to understand. Only certain objects would have these methods, so it would be easy to tell (via the rdocs) which elements supported them. Regardless, of the interface, let me move to discussing how to implement them. This week i created a new Locator class (TaggedElementLocator) and i expect to be refactoring the code to create more. I've long thought that the locator methods, currently in the container class, really belonged in the element classes -- because it is the class of the element that determines what locator method is use. By creating separate classes for them, this ultimately facilitates this move. The urgent motivation for this change was that i needed to implement multiple attribute selection. But i also had this issue in mind as i worked on it. I think the right solution now mainly amounts to creating a ChildRowLocator and ChildCellLocator subclasses, refactoring TaggedElementLocator to isolate the call that now appears as the first line of locate and then create new ChildRow and ChildCell subclasses of Row and Cell, with modified locate methods. Since the child_row and child_cell factory methods (a factory method is a method that creates an object -- the def_creator class method that is used to create most of these factory methods is not a factory method, but rather a factory method factory, if you want to call it that) would only be defined for containers that make sense (Table, Row), there is no need to check the class of the container. In other words, not only is this approach pretty easy for users to comprehend, it is also fairly straight-forward to implement. However, the getElementsByTagName method is called from many different places within Watir, This is a code smell. One source of this duplication is the many show_* methods. Most could be replaced with simple calls to Collection#show. E.g. show_rows could be replace with rows.show (and child_rows.show). and one of the places is Container#locate_tagged_element, which uses getElementsByTagName for many different tag types. This is the call that is now delegated to the new Locator class. The problem > with this is that while the same method is used to get ALL tags of a > given type, each DOM element has it's own *specfic* method to return the > collection of specific child nodes (like "rows" for table rows, "cells" > for table cells, etc). > Right. So you need to change the locate method of ChildRows and ChildCells to use your new locators instead. (Just instantiate and call them directly in the element locate method -- there is no reason to include the container in the delegation chain. How does this sound? -------------- next part -------------- An HTML attachment was scrubbed... URL: From davids at tower-mt.com Wed Jun 14 20:00:35 2006 From: davids at tower-mt.com (David Schmidt) Date: Wed, 14 Jun 2006 17:00:35 -0700 Subject: [Wtr-development] Table Row Bug -- How to fix? In-Reply-To: References: Message-ID: <4490A323.8080502@tower-mt.com> Bret Pettichord wrote: > Now for David's question. > > 1. I think that it is pretty safe to change row_count to only count > the rows that belong to a table. I said this on wtr-general and there > was no dissent and i think i was understood. There may be a problem with just fixing row_count because of the way it is used. In addition, there is a problem with *which* rows will be retrieved even if the row_count is fixed to only show the row count for each table and ignore rows in sub-tables. The problem comes into play when you go to retrieve the rows (and this applies to any container for which there can be many sub-containers, like cells or divs). For example, in our current unit tests we have table1.html which contains a sub-table in one of the tables. I did a fix to the row_count and thought that things were fine when I did the following test: t = ie.table(:index, 3) # the table which contains another table t.rows.length => 2 t.rows.each {|r| puts r.html} That showed me the two rows in the parent table and I thought all was good. So, I made the same type of changes for cells and spotted a problem which affects rows too. The problem is that the elements returned by .each (from getElementsByTagName()) are returned in the order that they appear in the container element. For our table in table1.html they would appear as row1 of table3, row2 of table3 and then row1 of table4. When I only displayed the first two rows things looked fine. However, table4 (the sub-table) is located in row2, cell1, so when I used the same method to show cells for each row like this: t = ie.table(:index, 3) # the table which contains another table t.cells.length => 4 t.cells.each {|c| puts c.html} Instead of getting the 4 cells from table 3, I got: cell 1 # row 1 cell 1 cell2 # row 1 cell 2 # row 2 cell 1, containing the entire sub-table
nest1 nest2
nest1 # OOPS!, this is row 1 cell 1 the sub-table, table4. This is because the cells are returned in the order that they are seen in the HTML document, so the first cell of the sub-table (containing "nest1") appears immediately after cell containing the sub-table. In order to get the correct items we need to use a different method other than getElementsByTagName whenever we want *just* the directly child elements. > 2. I originally thought that changing Watir so that ie.table(x).row(y) > would only reference rows that belonged to the specified table would > be safe, but as i've thought more about it and reflected on how i've > used Watir, i think that there is a pretty good chance that changing > this would break tests. In our DataCert application, we make commonly > reference tables as generic scoping containers and cells as types of > objects. We wrap the watir calls in an abstraction layer, so this > isn't immediatly clear to a scripter. But if we made it so that calls > to cell() would be restricted to child cells when the container was a > table, then that would probably break things for us. > > David's suggestion to use different semantics based on attribute is > not appealing to me. For one, because it simply is too difficult to > expect average users to understand. And secondly, because it seems to > break down if we consider the possibility of multiple attributes, > which i've started to commit code for, and am using for table cells, > among other objects. The idea of multiple attributes offers another > possibility: another attribute that specifies whether we should > restrict the collection to child elements. Maybe > ie.table(x).row(:belongs_to => true, index => 1). But i think i have a > better idea. > > A new method, ie.table(x).child_row(:index => 1). A child_row would be > just like another Row, except it would use a different locator method. > > Anyway, that is my proposal. It would mean adding child_row and > child_cell to the Table and Row classes. It wouldn't break any tests. > And i think that it would be pretty easy to understand. Only certain > objects would have these methods, so it would be easy to tell (via the > rdocs) which elements supported them. > > Regardless, of the interface, let me move to discussing how to > implement them. > > This week i created a new Locator class (TaggedElementLocator) and i > expect to be refactoring the code to create more. I've long thought > that the locator methods, currently in the container class, really > belonged in the element classes -- because it is the class of the > element that determines what locator method is use. By creating > separate classes for them, this ultimately facilitates this move. The > urgent motivation for this change was that i needed to implement > multiple attribute selection. But i also had this issue in mind as i > worked on it. > > I think the right solution now mainly amounts to creating a > ChildRowLocator and ChildCellLocator subclasses, refactoring > TaggedElementLocator to isolate the call that now appears as the first > line of locate and then create new ChildRow and ChildCell subclasses > of Row and Cell, with modified locate methods. Since the child_row and > child_cell factory methods (a factory method is a method that creates > an object -- the def_creator class method that is used to create most > of these factory methods is not a factory method, but rather a factory > method factory, if you want to call it that) would only be defined for > containers that make sense (Table, Row), there is no need to check the > class of the container. In other words, not only is this approach > pretty easy for users to comprehend, it is also fairly > straight-forward to implement. > > > However, the > getElementsByTagName method is called from many different places > within > Watir, > > This is a code smell. One source of this duplication is the many > show_* methods. Most could be replaced with simple calls to > Collection#show. E.g. show_rows could be replace with rows.show (and > child_rows.show). > > and one of the places is Container#locate_tagged_element, which > uses getElementsByTagName for many different tag types. > > This is the call that is now delegated to the new Locator class. > > The problem > > with this is that while the same method is used to get ALL tags of a > given type, each DOM element has it's own *specfic* method to > return the > collection of specific child nodes (like "rows" for table rows, > "cells" > for table cells, etc). > > > Right. So you need to change the locate method of ChildRows and > ChildCells to use your new locators instead. (Just instantiate and > call them directly in the element locate method -- there is no reason > to include the container in the delegation chain. > > How does this sound? First, a couple of notes about the implementation above. This problem will occur in any container that can contain another of it's own kind as a sub-container. Unfortunately, while the getElementsByTagName is the method used by all the containers to retrieve ALL tags below the current point, the method used to get just the child elements has a different name for different containers, like "rows" for a table's direct rows, and "cells" for a tables direct cells. My first test implementation to fix the problem used the "children" method, which should be available from each container. One problem with writing a "generic" getChildElements is that rows and cells are NOT direct descendants of tables. Rows may be contained in THEAD, TFOOT or TBODY elements, and cells may be contained (http://www.w3.org/TR/html4/struct/tables.html). This means you have to put in special code to find all rows for a given table, or all cells for a given row because the rows will be children of a table child: irb(main):078:0> t.document.children.each {|child| puts child.tagName} TBODY irb(main):079:0> t.document.children['0'].children.each {|child| puts child.tagName} TR TR Even the DOM can be inconsistent at times. For example, check out all of the collections at http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/collections.asp. Some return ALL items in the document, others return all children below a container and some return only direct descendants of a container. The "cells" collection is even more interesting. If called from a table element it will return all cells in the current table, but if called from a row it will return just cells in that row (ignoring cells in sub-tables in either case). So, no matter what we decide to do, there will be a bunch of special code to handle special cases. Bleah. Second, I would like to see our methods match, as closely as possible, the DOM methods. This would imply that our "rows" method will return just the rows for the current table, and will ignore sub-tables. Obviously, this *will* break current tests. So, how about another way to do this which will maintain current functionality while adding new functionality and yet giving the users a choice of how they want the current commands to work. My suggestion is this. We implement Bret's suggestion above as getChildElementsByTag, using the current Watir method names with "child_" prepended. I.E., "table().child_rows", "table().child_cells", etc. We also implement method names to explicitly show the current functionality by prepending "all_" to each current method. I.E., "table().all_rows" or "table().all_cells" which would *by default* work just like "table().rows" and "table().cells". Lastly, we create a configuration variable which will allow testers to *change* which methods the old names use, with the default to be set to leave them as they are now. For example, "table().rows" would give ALL rows below a table, even rows in sub-tables unless (for example) the tester set @@collection_retrieval_style to "child", in which case "table().rows" would return only the rows in that table. "Row_count" (and "cell_count") would also have additional methods like "all_row_count" and "child_row_count" and the default would be the current "all_" method. We could then recommend that tests be coded to use the more explicit method names, and someday we could possibly change the default if we wanted, but for now all current tests would run as-is, but people desiring the "new" behavior could turn it on if they wanted, and people needing *both* behaviors would have ways to make that clear in their scripts by using "all_" or "child_" for all the methods. I'd recommend that we document *both* styles in a table which would show the equivalent DOM methods to make it clear what elements will be returned by each of the four methods ("all_", "child_", default(current), optional(by setting an option)). Current unit tests would run as they do now, but we could add unit tests for the "all_" or "child_" versions along with tests which would test the behaviors of the old commands with the configuration switched. I'll volunteer to do the implementation and can probably have some trial versions ready in a day or two. David From bret at pettichord.com Thu Jun 22 14:01:07 2006 From: bret at pettichord.com (Bret Pettichord) Date: Thu, 22 Jun 2006 13:01:07 -0500 Subject: [Wtr-development] Performance Improvement Message-ID: David, Thanks for the recent performance improvement http://svn.openqa.org/fisheye/changelog/watir?cs=1046 You may be interested to know that in Ruby 1.6, if you returned from within a WIN32OLE.each block, you got a LocalJumpError. That's why the pre-existing code was so inefficient. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Fri Jun 23 11:33:10 2006 From: bret at pettichord.com (Bret Pettichord) Date: Fri, 23 Jun 2006 10:33:10 -0500 Subject: [Wtr-development] Performance Improvement In-Reply-To: References: Message-ID: I have another followup comment. 1046 created by > inetdavid on 22 June 2006, 02:39:36 -0500 (31 hours ago) (patch) > After profiling a web scraper that was running much slower with 1.5.1 than > with 1.4.1 > I found that 69% of the time was spent in locate_input_element(), almost > all of that time > in WIN32OLE#each. I saw that the each loop was continuing to run even > after an object > was found, so I re-wrote the loop so that the routine returns a value as > soon as one > is found and now that routine is only using 57% of CPU on the same test. > One problem with profiling is that it ignores the #1 cause of delay with Watir scripts -- sleeps. In general, i've made suites perform better by tweaking polling loops and reducing the time spent sleeping. But sleep-time is not counted as CPU time by the profiler, so it is effectively ignored. In other words, profiling makes code more efficient, but not necessarily faster. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: From davids at tower-mt.com Thu Jun 22 20:53:46 2006 From: davids at tower-mt.com (David Schmidt) Date: Thu, 22 Jun 2006 17:53:46 -0700 Subject: [Wtr-development] Performance Improvement In-Reply-To: References: Message-ID: <449B3B9A.1080008@tower-mt.com> Even with that restriction, the "next" should have been a "break" to break out of the each loop as soon as a match was found. With the "next" the process looped over all values, even after a match was found. Glad to help though. We're seeing things running much slower under 1.5.1 so we're looking for things to speed up, and I may find some more for you. I'm also still waiting for an answer to the proposal for how to handle the collections count issues on wtr-development. David Bret Pettichord wrote: > David, > > Thanks for the recent performance improvement > > http://svn.openqa.org/fisheye/changelog/watir?cs=1046 > > You may be interested to know that in Ruby 1.6, if you returned from > within a WIN32OLE.each block, you got a LocalJumpError. That's why the > pre-existing code was so inefficient. > > Bret > ------------------------------------------------------------------------ > > _______________________________________________ > Wtr-development mailing list > Wtr-development at rubyforge.org > http://rubyforge.org/mailman/listinfo/wtr-development -------------- next part -------------- An HTML attachment was scrubbed... URL: From davids at tower-mt.com Mon Jun 26 18:57:45 2006 From: davids at tower-mt.com (David Schmidt) Date: Mon, 26 Jun 2006 15:57:45 -0700 Subject: [Wtr-development] Performance Improvement In-Reply-To: References: Message-ID: <44A06669.3030805@tower-mt.com> Bret Pettichord wrote: > I have another followup comment. > > 1046 > created by inetdavid on 22 June 2006, 02:39:36 -0500 (31 hours > ago) (patch > ) > > After profiling a web scraper that was running much slower with > 1.5.1 than with 1.4.1 > I found that 69% of the time was spent in locate_input_element(), > almost all of that time > in WIN32OLE#each. I saw that the each loop was continuing to run > even after an object > was found, so I re-wrote the loop so that the routine returns a > value as soon as one > is found and now that routine is only using 57% of CPU on the same > test. > > > One problem with profiling is that it ignores the #1 cause of delay > with Watir scripts -- sleeps. > > In general, i've made suites perform better by tweaking polling loops > and reducing the time spent sleeping. But sleep-time is not counted as > CPU time by the profiler, so it is effectively ignored. > > In other words, profiling makes code more efficient, but not > necessarily faster. > > Bret I'm using the latest ruby-prof gem (version 1.4.1) and it does account for time spent in Kernel#sleep. Watir::IE#wait was the biggest caller of sleep (as expected) with #until_with_timeout being the second biggest as I'm using it to watch AJAX "spinners" until they disappear before I fill the following field. My timers account for both of those with code that starts a timer before every click and then stops after a page (or AJAX update) is finished loading. Using WIN32OLE#each is a performance killer because OLE calls are relatively expensive. I doubled the speed of my scraper's screen filling with this change because almost all elements are located using :id or :name, and this patch lets Watir locate an :id object in one call, and a :name collection in one call plus one call for every element with that name. Only hassle is that getElementById will return an element that happens to have a matching name attribute, which may be what most people *want* to happen, but isn't entirely accurate and will break tests where there are two elements of the same type where one has an id attribute and the other has a name attribute that matches. David David From bret at pettichord.com Mon Jun 26 19:35:09 2006 From: bret at pettichord.com (Bret Pettichord) Date: Mon, 26 Jun 2006 18:35:09 -0500 Subject: [Wtr-development] Performance Improvement In-Reply-To: <449B3B9A.1080008@tower-mt.com> References: <449B3B9A.1080008@tower-mt.com> Message-ID: On 6/22/06, David Schmidt wrote: > > Even with that restriction, the "next" should have been a "break" to > break out of the each loop as soon as a match was found. With the "next" > the process looped over all values, even after a match was found. > A break inside the each block would also caused a LocalJumpError in Ruby 1.6 . > Glad to help though. We're seeing things running much slower under 1.5.1so we're looking for things to speed up, and I may find some more for you. > I'm also still waiting for an answer to the proposal for how to handle the > collections count issues on wtr-development. > Right. -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Tue Jun 27 01:08:22 2006 From: bret at pettichord.com (Bret Pettichord) Date: Tue, 27 Jun 2006 00:08:22 -0500 Subject: [Wtr-development] Performance, Locators and the Strategy Pattern. Message-ID: David, I have two concerns about your recent changes. http://svn.openqa.org/fisheye/changelog/watir?cs=1049 http://svn.openqa.org/fisheye/changelog/watir?cs=1048 After more profiling I was seeing locate_input_element using over 60% of all > time during > one of my web scraper tests. Total time for the test was about 4 minutes, > with one minute > of that waiting for page loads. > > Most of my field lookups are by :id or :name so I checked for those > "how's" and instead > of iterating through all page elements I used the OLE getElementById and > getElementsByName > to find the element or collection. > > The performance difference is amazing. Before the 4 line change > locate_input_element took > 54.26% of the run time for my scrape. After this change it took 0.63%. > Run time went from > 3 minutes (ignoring page load times) down to about 1 minute (also ignoring > page load times). > > I'll keep looking for other ways to speed up Watir by using IE DHTML > methods to minimize > iterating through page elements one at a time. > > Previous patch had a problem with elements that didnt have getElementById > or getElementsByName. > This version fixes that by falling back to the previous method, but still > fails one unit test > where getElementByID returns an element with a matching name, but NO id. > I'll work tomorrow > on a fix for these conditions where the IE calls are "lying" 1. First of all, I'm unhappy seeing the addition of an unconstrained rescue block. I've been adding contstraints to the existing rescue blocks (i.e. specifying what error we trapping, rather than trapping all). We've had problems in the past with these kinds of rescue statements swallowing error messages. They really need to be used as a last resort at all, and when they are used, they should be should have the minimal scope (both lexically and in terms of the error trapped) as possible. 2. It's unclear to me how this performance enhancement coordinates with adding multiple attribute support. The multiple attribute support, at this time, is only attached to non-input elements and your performance improvement is attached to input elements, so there is not an immediate conflict. I'd appreciate if you gave this some thought. Ultimately, i think the need to trap errors was showing a flaw in the design -- namely the fact that your streamlined approach is not really put in the right place. The problem is that your alternates only for PageContainer#ole_inner_element and not for Element#ole_inner_element. The correct solution needs to use object-oriented design, rather than error trapping to ensure that the correct algorithm is used. Frankly these changes as well as the agreed need for a way to restrict locators to the immediate children of tables and rows point to the need for Locator classes along the line of what i've already done for non-input elements. Could you please take a look at TaggedElementLocator and think about how we can work together to develop this approach. The problem is that the locator algorithm depends on the type of element, the type of container and the type of attribute. And this is complicated more by the fact that the we are now supporting multiple attributes. With at least three dimensions, simple polymorphism isn't going to be enough to keep our code from being narly. If you read Design Patterns, TaggedElementLocator is an example of the Strategy Pattern. Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Tue Jun 27 13:40:33 2006 From: bret at pettichord.com (Bret Pettichord) Date: Tue, 27 Jun 2006 12:40:33 -0500 Subject: [Wtr-development] Table Row Bug -- How to fix? In-Reply-To: <4490A323.8080502@tower-mt.com> References: <4490A323.8080502@tower-mt.com> Message-ID: It has taken me a long time to reply to David's suggestions. There are a number of issues here and i think we really need to try to separate them. First of all, there is the general issing of giving Watir the ability to navigate specifically to the child rows and cells of a table (or row). I think everyone agrees this would be a valuable addition to Watir. So there is the discussion of how to do this. Then there is the issue of whether we should change the existing behaviour. I have found, not always to my pleasure, that the Watir user community is very conservative. They don't like Watir to change. Mostly, i think this is understandable. For most, Watir is a tool that helps them manage change and they don't want it changing, too. One of the reasons i've been slow to officially release 1.5 is because once it is released, many of the API's are going to be very hard to change. I have a number of changes i want to make and a number of new features that i want to have time for feedback and the opportunity to change the interfaces before this resistance sets in. David, you should realize that your usage of Watir differs from the bulk of our users (because you use it for scraping rather than testing) and that your context forces you to ready to deal with unpredictable and unanticipated change. Testers need to be able to understand change (i.e. whether it represents a bug or not) whereas with scraping it's just something to you have to deal with. I said, nonetheless, that it was probably safe to change row_count to only count the rows that are children of the table. I say this because i think most testers are using this to verify that some table has the right number of rows, which represent some kind of object (e.g. items in an order) and ultimately they are unaware of the fact that this count could represent something else. In other words, this change is welcome because our users have perceived the existing behavior as a bug. On the other hand, changing the behavior of the row and cell and rows and cells methods will be harder to convince our users to accept. Or me. Let me explain a concrete example. I've build a library for my application that allows me to express scripts in terms of how we percieve our application's controls -- rather than how they are implemented in html. So we have buttons, but they are not html buttons, but rather compound objects consisting of a div containing a table that contains cells with links and images and text. In our library, button('foo') returns a watir object that can be clicked. I think currently it returns the link or the div, but it could just as well return a cell. We also have panels which contain different sections of a page. These panels have a box around them and are implemented as html tables. For us, panel('foo') returns the Watir::Table corresponding to the panel that has a title of 'foo' (actually the text in a cell of a particular class). We mostly use these when we have multiple controls with the same name on a page. So panel('foo').button('search') returns the button (really, say, a cell) in the panel (a table). But note that we are not looking for a cell that is a child of the panel table (which in this case it is not). This is just one example of where we have cell in a table, with no assumption that the cell is a child of the table. Making David's suggested change would break code like this. Of course it would be easy for me to update my library to use the new methods, if thought they were a good idea. But my point is really that i'm sure other users are also using cells in tables without care for whether they are children of the tables. It's a reasonable thing to do. I should point out that the way that Watir, first, allows users to easily access any element without concern for how deep it is in the hierachy has been key to its ease of use. And secondly, that our use of containers (forms, tables, divs) to restrict the scope of a search is a key usability feature (this is much more general in 1.5 than it was in 1.4). In other words, Watir flattens the html hierarchy, but allows users to make use of it when it is convenient. This flattening is a key aspect of Watir. Previously i've used testing tools that made it much harder to flatten the hierarchy, and did not provide the flexibilty to allow you to use it only when you needed it. I noticed that a Watij user recently reported a bug where the equivalent of link(:text, 'foo') did not work when 'foo' was not the value of the actual link element, but rather the value of a contained element. I don't think we've ever had a bug like this in Watir: the flattening concept has been with us from day one. At the same time, i acknowledge that many users have been confused when they learn that our commands for cells and rows are not restricted to actual children. This is why i think it would be good to add these as new commands (child_row, child_cell, child_rows and child_cells). If we were working from a clean slate, we could have a fair consideration over which behavior should attach the simpler names (row, cell). But in the existing case, we have to acknowledge reality, which is that there is a bias against changing the behavior of existing methods. David, even if i haven't convinced you that we need to keep the existing behavior, i must nonetheless insist that we table that issue until we have a concrete implementation of the new behavior. I made the mistake of not separating the issues of new functionality and changing default behavior in my recent proposal regarding wait_until. I suggest that we change Watir to automatically wait for an object to exist before allowing other methods to act on it, but there was a fair amount of confusing around exactly what i was proposing. That confusion was sufficient that even though i arguably got consensus for my proposal, i decided to treat that as void. What i should have done was focus on the new "wait_until" syntax and behavior, get that implemented and then use that concrete implementation going forward as the basis for making my proposal that we change the default behavior. And that in fact is how i plan to move ahead with that idea. (A half-built version of wait_until is in trunk.) So that means that we need to move forward with how to implement child_row, child_cell, child_rows, and child_cells. I'll take up that technical issue in a later email. (Although my short answer is: use the Strategy Pattern and create locator classes.) Bret On 6/14/06, David Schmidt wrote: > > Bret Pettichord wrote: > > Now for David's question. > > > > 1. I think that it is pretty safe to change row_count to only count > > the rows that belong to a table. I said this on wtr-general and there > > was no dissent and i think i was understood. > There may be a problem with just fixing row_count because of the way it > is used. In addition, there is a problem with *which* rows will be > retrieved even if the row_count is fixed to only show the row count for > each table and ignore rows in sub-tables. My understanding is that you are saying we could actually fix row_count, but there is also a separate, but related problem. Right? The problem comes into play when you go to retrieve the rows (and this > applies to any container for which there can be many sub-containers, > like cells or divs). For example, in our current unit tests we have > table1.html which contains a sub-table in one of the tables. > > I did a fix to the row_count and thought that things were fine when I > did the following test: > > t = ie.table(:index, 3) # the table which contains another > table > t.rows.length => 2 > t.rows.each {|r| puts r.html} > > That showed me the two rows in the parent table and I thought all was > good. So, I made the same type of changes for cells and spotted a > problem which affects rows too. The problem is that the elements > returned by .each (from getElementsByTagName()) are returned in the > order that they appear in the container element. For our table in > table1.html they would appear as row1 of table3, row2 of table3 and then > row1 of table4. When I only displayed the first two rows things looked > fine. > > However, table4 (the sub-table) is located in row2, cell1, so when I > used the same method to show cells for each row like this: > > t = ie.table(:index, 3) # the table which contains another > table > t.cells.length => 4 > t.cells.each {|c| puts c.html} > > Instead of getting the 4 cells from table 3, I got: > > cell 1 # row 1 cell 1 > > cell2 # row 1 cell 2 > > # row 2 cell 1, containing the entire sub-table > > >
nest1 > nest2
> > nest1 # OOPS!, this is row 1 cell 1 the sub-table, table4. > > This is because the cells are returned in the order that they are seen > in the HTML document, so the first cell of the sub-table (containing > "nest1") appears immediately after cell containing the sub-table. > > In order to get the correct items we need to use a different method > other than getElementsByTagName whenever we want *just* the directly > child elements. > > > 2. I originally thought that changing Watir so that ie.table(x).row(y) > > would only reference rows that belonged to the specified table would > > be safe, but as i've thought more about it and reflected on how i've > > used Watir, i think that there is a pretty good chance that changing > > this would break tests. In our DataCert application, we make commonly > > reference tables as generic scoping containers and cells as types of > > objects. We wrap the watir calls in an abstraction layer, so this > > isn't immediatly clear to a scripter. But if we made it so that calls > > to cell() would be restricted to child cells when the container was a > > table, then that would probably break things for us. > > > > David's suggestion to use different semantics based on attribute is > > not appealing to me. For one, because it simply is too difficult to > > expect average users to understand. And secondly, because it seems to > > break down if we consider the possibility of multiple attributes, > > which i've started to commit code for, and am using for table cells, > > among other objects. The idea of multiple attributes offers another > > possibility: another attribute that specifies whether we should > > restrict the collection to child elements. Maybe > > ie.table(x).row(:belongs_to => true, index => 1). But i think i have a > > better idea. > > > > A new method, ie.table(x).child_row(:index => 1). A child_row would be > > just like another Row, except it would use a different locator method. > > > > Anyway, that is my proposal. It would mean adding child_row and > > child_cell to the Table and Row classes. It wouldn't break any tests. > > And i think that it would be pretty easy to understand. Only certain > > objects would have these methods, so it would be easy to tell (via the > > rdocs) which elements supported them. > > > > Regardless, of the interface, let me move to discussing how to > > implement them. > > > > This week i created a new Locator class (TaggedElementLocator) and i > > expect to be refactoring the code to create more. I've long thought > > that the locator methods, currently in the container class, really > > belonged in the element classes -- because it is the class of the > > element that determines what locator method is use. By creating > > separate classes for them, this ultimately facilitates this move. The > > urgent motivation for this change was that i needed to implement > > multiple attribute selection. But i also had this issue in mind as i > > worked on it. > > > > I think the right solution now mainly amounts to creating a > > ChildRowLocator and ChildCellLocator subclasses, refactoring > > TaggedElementLocator to isolate the call that now appears as the first > > line of locate and then create new ChildRow and ChildCell subclasses > > of Row and Cell, with modified locate methods. Since the child_row and > > child_cell factory methods (a factory method is a method that creates > > an object -- the def_creator class method that is used to create most > > of these factory methods is not a factory method, but rather a factory > > method factory, if you want to call it that) would only be defined for > > containers that make sense (Table, Row), there is no need to check the > > class of the container. In other words, not only is this approach > > pretty easy for users to comprehend, it is also fairly > > straight-forward to implement. > > > > > > However, the > > getElementsByTagName method is called from many different places > > within > > Watir, > > > > This is a code smell. One source of this duplication is the many > > show_* methods. Most could be replaced with simple calls to > > Collection#show. E.g. show_rows could be replace with rows.show (and > > child_rows.show). > > > > and one of the places is Container#locate_tagged_element, which > > uses getElementsByTagName for many different tag types. > > > > This is the call that is now delegated to the new Locator class. > > > > The problem > > > > with this is that while the same method is used to get ALL tags of a > > given type, each DOM element has it's own *specfic* method to > > return the > > collection of specific child nodes (like "rows" for table rows, > > "cells" > > for table cells, etc). > > > > > > Right. So you need to change the locate method of ChildRows and > > ChildCells to use your new locators instead. (Just instantiate and > > call them directly in the element locate method -- there is no reason > > to include the container in the delegation chain. > > > > How does this sound? > First, a couple of notes about the implementation above. This problem > will occur in any container that can contain another of it's own kind as > a sub-container. Unfortunately, while the getElementsByTagName is the > method used by all the containers to retrieve ALL tags below the current > point, the method used to get just the child elements has a different > name for different containers, like "rows" for a table's direct rows, > and "cells" for a tables direct cells. > > My first test implementation to fix the problem used the "children" > method, which should be available from each container. One problem with > writing a "generic" getChildElements is that rows and cells are NOT > direct descendants of tables. Rows may be contained in THEAD, TFOOT or > TBODY elements, and cells may be contained > (http://www.w3.org/TR/html4/struct/tables.html). > > This means you have to put in special code to find all rows for a given > table, or all cells for a given row because the rows will be children of > a table child: > > irb(main):078:0> t.document.children.each {|child| puts child.tagName} > TBODY > > irb(main):079:0> t.document.children['0'].children.each {|child| puts > child.tagName} > TR > TR > > Even the DOM can be inconsistent at times. For example, check out all > of the collections at > > http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/collections.asp > . > Some return ALL items in the document, others return all children below > a container and some return only direct descendants of a container. The > "cells" collection is even more interesting. If called from a table > element it will return all cells in the current table, but if called > from a row it will return just cells in that row (ignoring cells in > sub-tables in either case). > > So, no matter what we decide to do, there will be a bunch of special > code to handle special cases. Bleah. > > Second, I would like to see our methods match, as closely as possible, > the DOM methods. This would imply that our "rows" method will return > just the rows for the current table, and will ignore sub-tables. > Obviously, this *will* break current tests. So, how about another way > to do this which will maintain current functionality while adding new > functionality and yet giving the users a choice of how they want the > current commands to work. > > My suggestion is this. We implement Bret's suggestion above as > getChildElementsByTag, using the current Watir method names with > "child_" prepended. I.E., "table().child_rows", "table().child_cells", > etc. > > We also implement method names to explicitly show the current > functionality by prepending "all_" to each current method. I.E., > "table().all_rows" or "table().all_cells" which would *by default* work > just like "table().rows" and "table().cells". > > Lastly, we create a configuration variable which will allow testers to > *change* which methods the old names use, with the default to be set to > leave them as they are now. For example, "table().rows" would give ALL > rows below a table, even rows in sub-tables unless (for example) the > tester set @@collection_retrieval_style to "child", in which case > "table().rows" would return only the rows in that table. > > "Row_count" (and "cell_count") would also have additional methods like > "all_row_count" and "child_row_count" and the default would be the > current "all_" method. > > We could then recommend that tests be coded to use the more explicit > method names, and someday we could possibly change the default if we > wanted, but for now all current tests would run as-is, but people > desiring the "new" behavior could turn it on if they wanted, and people > needing *both* behaviors would have ways to make that clear in their > scripts by using "all_" or "child_" for all the methods. > > I'd recommend that we document *both* styles in a table which would show > the equivalent DOM methods to make it clear what elements will be > returned by each of the four methods ("all_", "child_", > default(current), optional(by setting an option)). > > Current unit tests would run as they do now, but we could add unit tests > for the "all_" or "child_" versions along with tests which would test > the behaviors of the old commands with the configuration switched. > > I'll volunteer to do the implementation and can probably have some trial > versions ready in a day or two. > > David > _______________________________________________ > Wtr-development mailing list > Wtr-development at rubyforge.org > http://rubyforge.org/mailman/listinfo/wtr-development > -------------- next part -------------- An HTML attachment was scrubbed... URL: From bret at pettichord.com Tue Jun 27 13:42:06 2006 From: bret at pettichord.com (Bret Pettichord) Date: Tue, 27 Jun 2006 12:42:06 -0500 Subject: [Wtr-development] Fwd: [Wtr-general] very neat trick with Ruby system() (or any otherlanguage on Windows) In-Reply-To: References: <4491DDC9.1040206@tower-mt.com> Message-ID: David, I did not see a response to my question below. Bret ---------- Forwarded message ---------- From: Bret Pettichord Date: Jun 16, 2006 1:53 PM Subject: Re: [Wtr-general] very neat trick with Ruby system() (or any otherlanguage on Windows) To: wtr-general at rubyforge.org On 6/15/06, David Schmidt wrote: > Bret, > > The current method is quite a bit different than the method that I > wrote, and I'm not sure it will be as flexible. (For example, you can't > attach to a Frame the way you can to an IE or Modal window.) My method > is designed to completely re-create the exact method string to get back > to the element to be clicked, and is working well for me right now, > though there are some inconsistencies with table related elements (which > is what got me looking at our current container/collection issue). Right. The method in trunk handles click_no_wait in all watir objects except frames. It is impervious to how we've implemented support for most controls and therefore is unaffected by the issues you've raised with table elements. To my thinking, that makes this code more flexible than what is in the modal_dialog branch. We just need to add support for frames. It's probably just two lines of code. I guess i can do it if you are uncomfortable with this approach. It's at https://svn.openqa.org/svn/watir/branches/modal_dialog/watir and > I'm doing lots of click_no_wait's from within frames. Feel free to > contact me if you have questions about the code in that branch as it's > pretty much my branch right now and it's probably a dead end until it's > decided to port that code to the current trunk. What do we have in there that isn't already in trunk, other than the frame/click_no_wait support? Bret -------------- next part -------------- An HTML attachment was scrubbed... URL: