Getting value from xpath query with and without selenium

Posted March 2nd, 2010 by Reinier Balt
Categories: Tracks

Using cucumber with webrat is not the same as using them with selenium. I found this out the hard way. In tracks, you have the ‘badge’ in the top-left corner which shows the number of items on the page. To check the number increases or decreases you want to retrieve the value of the badge.

I had:

xpath= "//span[@id='badge_count']"
response.should have_xpath(xpath) do |node|
  badge = node.first.content.to_i
end

Which did work without selenium, but selenium does not return a node to query. Instead AFAICS selenium wants:

xpath= "//span[@id='badge_count']"
response.should have_xpath(xpath)
badge = response.selenium.get_text("xpath=#{xpath}").to_i

Problem is that this cucumber step is used for features that require selenium and features that do not, so I ended up with

Then /the badge should show (.*)/ do |number|
  badge = -1
  xpath= "//span[@id='badge_count']"
  if Rails.env == 'selenium'
    response.should have_xpath(xpath)
    badge = response.selenium.get_text("xpath=#{xpath}").to_i
  else
    response.should have_xpath(xpath) do |node|
      badge = node.first.content.to_i
    end
  end
  badge.should == number.to_i
end

Not very nice, but functional.

Drag and drop in cucumber with selenium

Posted March 2nd, 2010 by Reinier Balt
Categories: Tracks

I needed to show a bug using a cucumber script which includes drag and drop. Turned out to be difficult for several reasons

  • drag and drop is not supported by webrat for selenium
  • ‘within’ for scoping is not supported by webrat for selenium

this made the feature difficult to quickly specifiy. The feature contains:

[...]
And I drag "Todo 3" to "Todo 2"
[...]
When I expand the dependencies of "Todo 1"
Then I should see "Todo 2" within the dependencies of "Todo 1"
[...]
For the drag you can do
drag_id = Todo.find_by_description(dragged).id
drop_id = Todo.find_by_description(target).id
drag_name = "xpath=//div[@id='line_todo_#{drag_id}']//img[@class='grip']"
drop_name = "xpath=//div[@id='line_todo_#{drop_id}']//div[@class='description']"
selenium.drag_and_drop_to_object(drag_name, drop_name)
This will work, but drag_and_drop does not wait for the ajax that is attached to the drop to finish. There is a wait_for_ajax, but this only works with Prototype, not with jQuery. If found a solution which is a bit of a hack, so I reverted to waiting_for the dependency arrow to appear:
arrow = "xpath=//div[@id='line_todo_#{drop_id}']/div/a[@class='show_successors']/img"
selenium.wait_for_element(arrow)
The next hurdle was to check if “Todo 1” as a dependency is shown in the dependency tree of “Todo 2”. There is a standard “I should see … within …” which comes with Cucumber, but unfortunately the webrat ‘within’ does not work for selenium :-(. Thus, this does not work:
xpath = "//div[@id='line_todo_#{todo.id}'"
Then "I should see \"#{successor_description}\" within \"xpath=#{xpath}\""
So I reverted to a xpath query on “Todo 1” within “Todo 2” like this:
xpath = "xpath=//div[@id='line_todo_#{todo.id}']//div[@id='successor_line_todo_#{successor.id}']//span"
selenium.wait_for_element(xpath)

UPDATE: In Tracks Eric added a change to show an image where to drop a todo. Problem is that the image only appears when dragging starts. Selenium does not have semantics for this, i.e. the drop target cannot be found when it is hidden before calling drag_and_drop_to_object.

I needed to ‘fix’ this by showing the image before I started the drag and drop. Somehow I also needed to use the id of the img. An xpath with the class did not seem to work:

  drag_name = "xpath=//div[@id='line_todo_#{drag_id}']//img[@class='grip']"
  drop_name = "xpath=//div[@id='line_todo_#{drop_id}']//img[@id='successor_target_#{drop_id}']"

  # the target img is hidden until drag starts. We need to show the img or the
  # xpath will not find it
  js="$('img#successor_target_#{drop_id}').show();"
  selenium.get_eval "(function() {with(this) {#{js}}}).call(selenium.browserbot.getCurrentWindow());"

  selenium.drag_and_drop_to_object(drag_name, drop_name)

Resulting patch here.

Geweldige Blue Screen of Death (BSOD)

Posted September 19th, 2009 by Reinier Balt
Categories: General

Tja, sommige BSOD’s zijn minder erg 🙂

Excel trucjes

Posted March 13th, 2009 by Reinier Balt
Categories: Profession, Tools

Ik heb me nooit echt verdiept in de mogelijkheden van Excel, maar nu ik een vervelend herhalend klusje in een excel moet uitvoeren ben ik me gaan verdiepen in een aantal handige mogelijkheden.

Voor mijn eigen referentie de volgende functies. De eerste functie is address waarmee je een referentie tekstueel kan samenstellen, bijvoorbeeld


ADDRESS(14;30;1;TRUE;CONCATENATE("Wk "; TEXT($A11;$A11)))

maakt een verwijzing naar AD14 (of eigenlijk $AD$14 vanwege de opvolgende parameter 1). Dit had overigens ook via ROW($AD$14) en COLUMN($AD$14) gedaan kunnen worden. De laatste parameter is een verwijzing naar het blad, in dit geval ‘Wk 10’ waarbij in $A11 het getal 10 staat. Ofwel de formule hierboven maakt een tekst aan ‘Wk 10’!$AD$14.

Met de tekst kan je niet veel, maar via de functie indirect kan je de waarde van die verwijzing ophalen:


=INDIRECT(ADDRESS(14;30;1;TRUE;CONCATENATE("Wk "; TEXT($A11;$A11)));TRUE)

Dit is dus hetzelfde als =’Wk 10’$AD$14

Maar je kan nu via copy-and-paste de formule eenvoudig laten varieren over de weeknummers. Immers zal via copy-and-past naar de volgende regel $A11 veranderen in $A12 waarin in dit geval het volgende weeknummer staat en dat levert ‘Wk 11’$AD$14 op.

Een ander trucje is het opzoeken van de laatst ingevulde waarde in een kolom. Heel handig voor kolommen die je regelmatig aanvult.

MAX(IF(LEN(B3:B39)>0;ROW(B3:B39);0))

Dit levert in deze vorm een foutmelding op. Maar als je de formule invoert en met Ctrl-Shift-Enter opslaat, zal Excel de formule per element van B3:B39 uitvoeren, waardoor het MAX van een array van rijnummers wordt bepaald. In het array zitten alleen rijnummers van cellen die gevuld zijn (LEN > 0).

Vervolgens kan je dit rijnummer in een formule gebruiken, bijvoorbeeld om het verschil van de laatst ingevulde waarde in B3:B39 met een startwaarde in A3 te berekenen:

=INDIRECT(ADDRESS(MAX(IF(LEN(B3:B39)>0;ROW(B3:B39);0));COLUMN(B3)))-A3

Deze trucjes zoek je eenmalig uit en vergeet je daarna weer, vandaar deze post 🙂

Lost theorie

Posted October 2nd, 2008 by Reinier Balt
Categories: Life

Zoals velen zijn Fleur en ik trouwe volgers van de Lost serie. Daarbij overigens vaak gefrustreerd omdat NET5 altijd besluit om midden in een seizoen te stoppen 🙁

Op internet zijn er verschillende theorieen over Lost. Leuk om zo nu en dan te lezen. Deze post is wel heel mooi met prachtige uitgewerkte tijdlijnen. Mooie visualisaties overigens. Of het waar is…

efficienter werken

Posted September 5th, 2008 by Reinier Balt
Categories: GTD, Life

 

Productivity Tips

Leuke post over een whiteboard met slimme productiviteitstips. Wordt ook gerefereerd aan ‘filing success’. Ik ben daar net een boek over aan het lezen. Beetje zweverig geschreven, maar de kerntips zijn wel handig.

Mozilla’s Ubiquity

Posted September 5th, 2008 by Reinier Balt
Categories: News, Profession, Tools

Interessante ontwikkeling is dit. Mozilla is bezig met een plugin om snel acties te kunnen doen op het web. Heb je een adres, selecteer het, kies ‘map’ en het wordt via Google Maps op een kaart gezet. Of wil je een deel van een pagina emailen? Selecteer het deel en tik ’email iemands@dres.nl’. Ziet er handig uit. Op de Ubiquity website staan meer voorbeelden.

Upgrade naar WordPress 2.5

Posted April 2nd, 2008 by Reinier Balt
Categories: Blogging

Dit is wel heel makkelijk. Unzip de bestanden over de bestaande installatie, naar een upgrade pagina en klaar! En we draaien onder WordPress 2.5