Watir, find input elements by (dynamically generated) id

June 24th, 2010 dwright 1 comment

problem space:
web testing, using watir. Need to find the status of a radio button which has a dynamically generated id

html:

<div id="9_status_544_654321">
<!-- On -->
<input type="radio" id="9__status_544_on__654321" value="on"/>
<!-- Off -->
<input type="radio" id="9__status_544_off__654321" value="off"/>
</div>

watir:
(we know the first and last values in the string, but not the middle value,
i.e. 9__status_(?)_off__654321)

   id1, id2 = 9, 654321
    re = Regexp.new("#{id1}__status_\\d+_on__#{id2}")
    p @ie.radio(:id, re).text   # prints 'checked'
    p @ie.radio(:id, /re/).text # also prints 'checked'
Categories: watir Tags:

jQuery, containing div, get id’s for all children

June 22nd, 2010 dwright No comments

problem space:
use jQuery to find all the (child) div's (id) within a containing div.

html:

<div class="top">
  <!-- dynamically generated div's -->
  <div id="7_status_854_5234"></div>
  <div id="54_status_54_5234"></div>
  <div id="23_status_27_5234"></div>
</div>

jQuery:

//get all children's div id
var children_ids = [];
$("div.top").contents().filter(
  function(){
    if (this.nodeType == 1) { // nodeType 1 => div
      // reg exp matches div
      var child_ids = this.id.match(/(\d+)_status_\d+_\d+/);
        try {
          children_ids.push(child_ids[1]);
        } catch(e){}
    }
  }
);

$.each(children_ids,  function(i,j){
  console.log(j);
});

// or maybe the more familiar, the non-jquery way
for(var i = 0 ; i < children_ids.length; i++){
  console.log(children_ids[i]);
}
Categories: jQuery Tags:

jQuery post (params) checkbox value even when unchecked

June 18th, 2010 dwright No comments

Problem space:
So, it's an (annoying) fact that html form element checkbox's only send their name=value pairs when they are checked, when they are not checked they don't send anything. (yes, really)

I think of checkbox's as bool's (true/false - on/off) so this is not the behavior I would expect.
There are several 'kludges' around this, many folks just add a hidden field with the same name as the checkbox (often dynamically generated) if the value is 'off'. (you can do a search for that solution).

Here is yet another approach, using jQuery, this does the same thing, but dynamically at submit time.

pros: less annoying than adding a hidden element for every checkbox
cons: slightly obfuscated, can silently fail leading to hard to decipher bugs

<script type="text/javascript" charset="utf-8">
    // do when submit is pressed
    $('form').submit(function() {
      var elements = this.elements;
      for (i=0; i < elements.length; i++) {
        // make sure checkboxes are in POST params even when 'off'
        if (elements[i].type == 'checkbox') {
          if (! $('#'+elements[i].id).is(':checked')) {
            var add_hidden_on_checkbox_off = $("<input>").attr("type",
                        "hidden").attr("name", elements[i].name).val("off");
            $('form').append($(add_hidden_on_checkbox_off));
          }
        }
       }
      //return false; // will not submit form, use to test with
    });
</script>

The above will send all checkbox's when the form is submitted, checked boxes will have the value 'on', unchecked boxes will have the value 'off'.

Side Note:
Originally I had:
if (elements[i].type == 'checkbox' && elements[i].value != 'on') {
but Firefox [3.6.3](Gecko) and Chrome [5.0.375.70](Webkit) handle this value differently.

Firefox will return 'on' whether the checkbox is checked or not, Chrome will return 'on' if the checkbox is checked and nothing if unchecked.

watir checkbox clear vs checked? vs value

June 18th, 2010 dwright No comments

Geez, what an unpleasant surprise this was.

Problem space:
Use Watir to test if a checkbox is checked or not and to uncheck it (clear).

Confession, I am actually now using Celerity in place of Watir. (So this could behavior may be with Celerity, not watir, I have not confirmed yet)

html:
<input type="checkbox" name="is_moveable" id="is_moveable" checked="yes"/>

celerity:
p @ie.checkbox(:name, 'is_moveable').value # returns 'on'
p @ie.checkbox(:name, 'is_moveable').checked? # returns true
assert @ie.checkbox(:name, 'is_moveable').clear # uncheck it
p @ie.checkbox(:name, 'is_moveable').value # returns 'on'
p @ie.checkbox(:name, 'is_moveable').checked? # returns false

I would think that if you cleared a checkbox with no value, that the value would be 'off', but I 'assume' the default value is 'on', so that is still the value returned.

In this situation use 'checked?' instead of 'value'

rails assert_no_select

April 2nd, 2010 dwright 1 comment

rails 2.2.* something has deprecated assert_tag in favor of the much less verbose assert_select.

In the case you want to verify that an element does not exist, one may expect, 'assert_no_select' which does not exist.

Here is the suggested method for finding the absence of a element:
assert_select ‘div’, :count => 0

Another method which works in many cases, is:
assert_select 'strong', 'Select a Region:' == false
assert_select 'select[id=rid]', true == false

element_by_xpath with two attributesx

March 30th, 2010 dwright No comments

Watir can not access the 'for' attribute of the 'label' element. Here is a work around.

html: <label class="error" generated="true" for="partner_status">This field is required.</label>

xpath: lpe = "//label[@class='error' and @for='partner_status']"
p @ie.element_by_xpath(lpe).text

will print: 'This field is required.'

Categories: ruby, watir Tags: ,

centos 5.4 rpmforge missing subversion-ruby-1.6.6

March 15th, 2010 dwright No comments

we are using subversion.x86_64 1.6.6-0.1.el5.rf and we require the Ruby bindings, subversion-ruby.x86_64.

However only 1.4.2-4.el5_3.1 (from base) is available. (which wont install, as it breaks deps. We can roll back to the base subversion, however there were some notable changes in svn > 1.5.0, (much improved merging, for example) which we do use

rpmforge is missing subversion-ruby.x86_64 1.6.6-0.1.el5.rf.
There is this bug: rpmforge lists

yum list|grep sub
subversion.x86_64 1.6.6-0.1.el5.rf installed
subversion-devel.x86_64 1.6.6-0.1.el5.rf rpmforge
subversion-javahl.x86_64 1.4.2-4.el5_3.1 base
subversion-perl.x86_64 1.6.6-0.1.el5.rf rpmforge
subversion-ruby.x86_64 1.4.2-4.el5_3.1 base

My work around for this:
(I would rather not build this from source)

luckily, I found: http://packages.sw.be/subversion/

wget http://packages.sw.be/subversion/subversion-1.6.6-1.el5.test.x86_64.rpm
http://packages.sw.be/subversion/subversion-ruby-1.6.6-1.el5.test.x86_64.rpm

yum uninstall subversion (luckily no deps)
sudo rpm -ivh subversion-1.6.6-1.el5.test.x86_64.rpm subversion-ruby-1.6.6-1.el5.test.x86_64.rpm

(NOTE: if you are also using something like enterprise ruby in a non standard location, you will have to tell it where to find svn)
something such as:
sudo ln -s /usr/lib64/ruby/site_ruby/1.8/x86_64-linux/svn /opt/ruby-enterprise-curr/lib/ruby/1.8/x86_64-linux/svn

Dictionary, word pairs code challenge

March 7th, 2010 dwright No comments

A few months ago, I came across a job posting with a code challenge to solve and submit with your resume.

I'm not in the job market but I generally like these sort of challenges and since the job is no longer listed, I will post what I came up with.

The Rules:
Given a dictionary, output all word pairs where both words
share all their letters except the last two, which are
distinct and reversed.

Notes:
- use a reasonable dictionary of your choice
- potential word pairs are: "ear, era" ; "revies, revise" ; "burglaries, burglarise"
- "shear, era" is not a valid pair because "she" != "e"
- "bell, bell" is not a valid pair because the last two letters are not distinct
- this will be benchmarked

Here is the final result I came up with, I don't have anything to compare it with, but I believe it's correct. (filter.pl)

# filter.pl
#to run:
#cat /usr/share/dict/words | perl filter.pl

use strict;
use warnings;
my $save_possible = {};

while (<>) {
   chomp $_;

   # lower case
   $_ = lc $_;

   # skip words smaller then 3 chars
   next unless length $_ >= 3;

   my $word_minus_2 = substr($_, 0, -2);
   my $last_2_chars_from_word = substr($_, length($_)-2, length($_));

   $save_possible->{$_} = $_;

   my $tmp = $_;
   # the last two chars of word, reversed
   my $last_2_chars_from_word_rev = chop($tmp);
   $last_2_chars_from_word_rev .= chop($tmp);

   if ($save_possible->{$word_minus_2.$last_2_chars_from_word_rev} #exists
       and ($_ ne $word_minus_2.$last_2_chars_from_word_rev)){#skip same word
      my $w2_rev=$save_possible->{$word_minus_2.$last_2_chars_from_word_rev};
      print "$_ -> $w2_rev\n";
     $save_possible->{$_} = undef; # skip dups
   }
}
real	0m0.992s
user	0m0.897s
sys	0m0.047s

Results verified with:

$ wc -l  /usr/share/dict/words
234936
$ time cat /usr/share/dict/words | perl filter.pl | sed -e 's/ ->.*//g' > OUT
$ wc -l OUT
565 OUT
$ grep -ciwf OUT  /usr/share/dict/words
565
=~ .2% of the words in this dict fit our criteria




Ok, now that I've posted that I will illustrate how the wrong assumptions can lead you down the wrong path, here was my original approach:

My assumption was that the cases would be consecutive.
i.e. (would exist lexicographically, in succession)
aab
aba

abel
able

ala
aal
...

So, my (as I thought, 'slick') idea was to use the Perl's native sort function, providing my own sorting routine, that should be very fast and I don't have to do much, great!

Here is my first draft in Perl: (yes, it's wrong - and ugly!)

#!/usr/bin/perl -w

#on my mac os x system one run's this as:
#$ cat /usr/share/dict/words | perl filter.pl

use strict;
use warnings;

my %possible = ();

sub _same {
   chomp $a;
   chomp $b;
   return -1 unless length $a > 1 && length $b > 2;

   my $last_two_a   = substr($a, length($a)-2, length($a));
   my $last_two_b_r = substr($b, length($b)-1, length($b));
   $last_two_b_r .= substr($b, length($b)-2, 1);

   if (((substr($a, 0, length($a)-2)
        cmp
         substr($b, 0, length($b)-2)) == 0)
        &&
       (($last_two_a cmp $last_two_b_r) == 0)){

         $possible{lc $a} = lc $b;
         return 0;
   }

   # we dont care about the returned sort, it's a byproduct
   return 1;
}

my @len_sort = sort _same <>;

foreach my $w (keys %possible){
  print "$w => $possible{$w}\n";
}
real    0m0.715s
user    0m0.660s
sys     0m0.053s

Great, results! and great performance, Well, that settles it, it must be working (haha).

One night a few weeks later, this popped into my head again (especially, since I had a feeling my approach was not accurate), so I revisited it.

Well, of course my 'ass'-umption was incredibly WRONG!

This approach does find some cases, I never bothered to really verify it, the quick eyeball said, 'geez, I would think there would be more, but ok,...'. (Ok, this is what I get for working past midnight all week)

After other attempts of trying to utilize Perl's native sort function. (I'll save you the from the example code, since at this point it's messy and complex, which alone is a red flag, since this should be simple!)

Basically by this point, it became clear that the sort method is not providing any benefit, is the wrong approach and is helping me to obfuscating the code in this specific situation.

That is when I came up with the approach I posted at the beginning. (I avoided doing this the first time because I thought, "I just need to compare consecutive words and how would I save the previous word, to compare with the next via an input stream" (i.e. without using global storage, saving all of them; and since I assumed they were consecutive, I would just provide a method to sort, which provides much for free. lazy! in a bad way). Had I realised, of course, that they are not consecutive I would have abandoned the sort method right off the bat.

Categories: perl Tags:

Perl XML well formed check

February 3rd, 2010 dwright No comments

Problem space:

Using Perl, you want to see if XML is 'valid'.

(it's actually just a 'well formed' check. To check validity, you would need to use the XML documents DTD, if one exists)

my $parser = XML::Parser->new( ErrorContext => 2 );
eval { $parser->parse( $data ); };
# report any error that stopped parsing
if( $@ ) {
    Carp::croak "ERROR: NOT WELL FORMED ELEMENT: $@\n";
}

Additionally, if you have a *NIX box available, xmllint should be installed, is available from the command line.

Categories: perl Tags:

Perl, Spreadsheet::ParseExcel, Parsing an XLS file with mixed encodings

February 3rd, 2010 dwright No comments

We are using the Perl module, Spreadsheet::ParseExcel->new to parse XLS files and insert the results into a UTF8 MySQL database.

I came across an interesting situation with a Microsoft Excel file, where only 3 fields of the 12 are encoded as UTF-16BE, the rest are latin1.

Parsing a file with mixed encoding returns unexpected results, since the data in the spreadsheet looks correct, but parsing in it one receives incorrect characters.

Here is some code using Encode::Guess which will resolve the mixed encoding issue.

my $enc = guess_encoding($text); # use Encode::Guess;
if (ref $enc) {
    $descr = decode($enc->name, $text);
}
else { # convert to utf8, does not turn on utf8 flag
  from_to($text, "iso-8859-1", "utf8");
}

or, if you are already expecting UTF8 data, or more specifically, data with the utf8 flag turned on (perl 5.8.* - see perldoc Encode)

use Encode qw/decode from_to/;
use Encode::Guess;
if (! utf8::is_utf8($val)) { # ok, its not utf8, what is it?
    my $enc = guess_encoding($val); # use Encode::Guess;
    if (ref $enc) {
        $val = decode($enc->name, $val); #turns on utf8 flag
    }
}

(you would have to use these on a field-by-field/val-by-val basis obviously)