SaaS + iPad = success

Posted August 6th, 2010 by Reinier Balt
Categories: Profession, Tracks

I had a nice experience yesterday. I found a pull request on Github for Tracks. I read the email notifying me of the request. Using the iPad went to GitHub, used their great Fork Queue function to cherry-pick it into master and replied to the ticket on Assembla. All using touch on the iPad :-) Very slick, very easy. Is the iPad revolutionary? I think it will change the way we browse the web in our living room for sure. Given that many SaaS applications in the cloud, who needs a laptop / desktop?

Handschrift herkenning Windows 7

Posted May 27th, 2010 by Reinier Balt
Categories: Profession, Tools

Leuk. Je hebt een laptop waarbij je bij de eerste start kiest voor Engels (ik heb een hekel aan sommige gekke vertalingen). Blijkt de handschrift herkenning niet te werken als je Nederlandse locale kiest. Door de keuze voor Engelse Windows wordt ook alleen de Engelse language pack geïnstalleerd. Alleen als je Windows 7 Ultimate of Enterprise hebt kan je meerdere language packs installeren…

Toen kwam ik deze site tegen. En het werkt. Nu heb ik Nederlandse handschrift herkenning op een engelse Windows 7 Home Premium…

Alle rechten op registry key weg

Posted April 19th, 2010 by Reinier Balt
Categories: Server, Tools

Bij het deinstalleren van een applicatie kwam een foutmelding rondom een registry sleutel. Na heel veel geklooi en gegoogle er achter gekomen dat op een of andere manier alle (maar dan ook alle) rechten weg waren. Een administrator account bleek niet in staat om weer rechten toe te voegen. Uiteindelijk gevonden dat je als System wel weer rechten kan instellen. Daarna kon de deinstallatie weer doorgaan.

De truc: psexec -s -i regedit

met deze tool van sysinternals kan een een applicatie starten onder system account. Gevonden via deze link.

How to drag and drop to a hidden target using selenium

Posted March 24th, 2010 by Reinier Balt
Categories: Tracks

See the update at the bottom on this post. Inspired by this posting by Pat Nakajima to execute the javascript to show an element before doing drag and drop.

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 :-)