My reusable Calabash steps

Written by: | Posted on:

As promised, here are my reusable Calabash steps. Now, some of these are probably more inspirational than reusable (or ignorable, if you like ;-) ), but this is ALL the steps I use SO FAR apart from the standard steps. Like I said before, there are so many great steps already defined, so check them out. Anyway, here they are, all 134 lines:

`Given /^I press the "([^\"]*)" tableviewcell button$/ do |cell|
touch("tableViewCell button marked:'" + cell + "'")
end

Given /^I press the "([^"]*)" label$/ do |label|
touch("view label text:'#{label}'")
end

Then /^I enter "([^\"]*)" in the "([^\"]*)" (?:text|input) field$/ do |text_to_type, field_name|
set_text("textField placeholder:'#{field_name}'", text_to_type)
sleep(STEP_PAUSE)
end

Given /^I press the "([^"]*)" segment$/ do |label|
touch("segmentedControl segment marked:'#{label}'")
end

Given /^I see the text "([^"]*)" to the right of the text "([^"]*)"$/ do |right, left|
leftRect = query("label {text LIKE '#{left}*'} parent view:'PdfThumbnailView'", :frame)[0]
screenshot_and_raise "Text \"#{left}\" could not be found" if(leftRect == nil)
leftX = Integer(leftRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
leftY = Integer(leftRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

rightRect = query("label {text LIKE '#{right}*'} parent view:'PdfThumbnailView'", :frame)[0]
screenshot_and_raise "Text \"#{right}\" could not be found" if(rightRect == nil)
rightX = Integer(rightRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
rightY = Integer(rightRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

screenshot_and_raise "The following texts should be on the same horizontal line: \"#{left}\" \"#{right}\"" if(leftY != rightY)
screenshot_and_raise "The text \"#{right}\" is not to the right of the text \"#{left}\"" if(leftX >= rightX)
end

Given /^I see the text "([^"]*)" beneath the text "([^"]*)"$/ do |bottom, top|
bottomRect = query("label {text LIKE '#{bottom}*'} parent view:'PdfThumbnailView'", :frame)[0]
screenshot_and_raise "Text \"#{bottom}\" could not be found" if(bottomRect == nil)
bottomX = Integer(bottomRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
bottomY = Integer(bottomRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

topRect = query("label {text LIKE '#{top}*'} parent view:'PdfThumbnailView'", :frame)[0]
screenshot_and_raise "Text \"#{top}\" could not be found" if(topRect == nil)
topX = Integer(topRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
topY = Integer(topRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

screenshot_and_raise "The following texts should be on the same vertical line: \"#{top}\" \"#{bottom}\"" if(topX != bottomX)
screenshot_and_raise "The text \"#{bottom}\" is not beneath the text \"#{top}\"" if(topY >= bottomY)
end

Given /^I don't see the "([^"]*)" button$/ do |expected_mark|
res = query "button", :accessibilityLabel
index = res.find_index {|s| s == expected_mark}
screenshot_and_raise "Index should be nil (was: #{index})" if (index != nil)
end

Given /^I scroll to "([^"]*)"$/ do |searchText|
res = query "TableView index:1 TableViewCell label", :text
row = res.find_index {|s| s == searchText}
scroll_to_row :tableView, row
sleep(STEP_PAUSE)
end

Given /^given I import "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"$/ do |datasource, maindir, subdir, file|
touch("tableViewCell label text:'All files'")
sleep(STEP_PAUSE)
touch("tableViewCell label text:'#{datasource}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{maindir}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{subdir}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{file}'")
sleep(STEP_PAUSE)
touch("tableViewCell label text:'All files'")
sleep(STEP_PAUSE)
end

Given /^given I import "([^"]*)", "([^"]*)", "([^"]*)"$/ do |datasource, maindir, file|
touch("tableViewCell label text:'All files'")
sleep(STEP_PAUSE)
touch("tableViewCell label text:'#{datasource}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{maindir}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{file}'")
sleep(STEP_PAUSE)
touch("tableViewCell label text:'All files'")
sleep(STEP_PAUSE)
end

Given /^I remove all my documents$/ do
docs = query("view:'PdfThumbnailView'")
docs.each do |pdfView|
touch("button marked:'EditCards'")
sleep(STEP_PAUSE)
touch("view:'PdfThumbnailView' index:0 button marked:'card function delete'")
sleep(STEP_PAUSE)
touch("button marked:'Delete file'")
sleep(STEP_PAUSE)
touch("button marked:'EditCards'")
sleep(STEP_PAUSE)
end
end

Given /^I remove all my folders$/ do
if(query("label marked:'My folders'").count > 0)
titleRect = query("label marked:'My folders' parent view", :frame)[0]
titleX = Integer(titleRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
titleY = Integer(titleRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

count = query("tableViewCell").count
i = 0
while i < count do
cellRect = query("view:'FolderTableViewCell' index:#{i} view", :frame)[0]
cellX = Integer(cellRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
cellY = Integer(cellRect[/{(.*), (.*)}, {(.*), (.*)}/,2])
if(cellX == titleX && cellY > titleY)
touch("view:'FolderTableViewCell' index:#{i} view")
sleep(STEP_PAUSE)
touch("view:'FolderTableViewCell' index:#{i} button")
sleep(STEP_PAUSE)
touch("segmentedControl segment marked:'Delete folder'")
sleep(STEP_PAUSE)

break
end
i = i + 1
end
end

macro %Q|I remove all my folders| if(query("label marked:'My folders'").count > 0)
end

Given /^I playback recording "([^"]*)" at label "([^"]*)"$/ do |movie, label|
playback movie, {:query => "label text:'#{label}'"}
end`

My build setup

Written by: | Posted on:

Tomorrow I begin work at Trifork! :-) There I'll be doing iOS development, so before I begin I thought I'd like to share a bit about how I do my development now.

First of all, I use GitHub and Beanstalk for source control, depending on what client the work is for (for my own projects, I use GitHub). Mercurial is nice, but git and svn just work with XCode, so I stick to that.

Since I have source control, I can have continuous delivery. For that I use Jenkins. Jenkins is not good enough. It's not great. It's not beautiful. It's not intelligent, easy, friendly, intuitive, or all those other nice words. But it works! I use the Clang Scan-Build, Github OAuth, Github, Pre SCM BuildStep, Redmine, SICCI, SSH Slaves and Xcode integration plugins, even though I'd get most things done by just adding a shell script. That gives me a build per commit, which is nice and reliable and brings the pain forward. Jay pain! ;-)

Of course, having this infrastructure in place begs for tests. Now I think tests for iPhone applications suck. Bigtime! The reason is that I hate deployment cycles. It takes time, and that time I'd rather use writing code, thinking about the application, solving real problems for my customer, preferably before he knows about them. If not that, I'd rather drink coffee, do chores in my home, or clean my pipes, rather than waiting for build cycles. It's just an enormous waste of time. And tests for iOS drain time, as there's no such thing as a unit test for iOS. Everything is an integration test or a user acceptability test. You always fire up the entire application before running any test.

So now I have that rant done, it's great that I can leave my tests to Jenkins. It will perform them, and the output will get converted to what looks like a JUnit test so that it can get picked up by Jenkins' tooling and be presented nicely. Jay! :-)

Then we get to deployment. My clients communicate with me. A lot! This should be different like so, I changed my mind about this, I've found a bug if you do like this and that. It's great! I love my users for this! It creates such a momentum! So how awful wouldn't it be if I said "I'll collect everything and give you a beta in three weeks"? Continuous delivery isn't just delivery to me, it is to the users as well. For this I use HockeyApp. They're a great bunch and really responsive, and while they just don't support iOS 5 well enough yet, there is so much good there. My app gets auto-deployed up there and my client sees the new release, hits install and boom! Now he's running the latest build! :-) Crash reports get sorted by build numbers, and the guys at HockeyApp have told me they're working at making the crash reports even more awesome! Jay! :-)

So how do I follow up on these things? I have to admit, I'm a cheapskate, so I use Redmine. I would use Basecamp, and I hope to be using it, it's so awesome, but so far it's not been worth the extra cost. The day it is, I'll run and buy it quickly. My problem with Basecamp and Redmine? I just haven't seen how I'd integrate it with my scrum sprints. Yet. I'm sure they both can, and I hope to learn from people that are wiser than me in this regard.

Finally, after a deployment to the appstore, I use Flurry to keep track of where my users are at, both in version of the app (why don't they upgrade! This new version is awesome! I need to tell them more about it!) and the OS (really? They're still on iOS 4?? iOS 5 has been out a month now! Oh well, not everyone is like me). Also, I've rolled my own crash reporting that, should I have failed horribly, the users can get in touch with me or the client, with a detailed log of what went wrong.

So, that's my work setup this far, and I'm quite happy with it. It still needs better scrum integration. It's still too many pieces that don't talk sensibly together. But it's getting better knit together, and I'm looking forward to seeing how Trifork does it, how I can improve based on what they have to teach, and how I can improve the way they're doing it. It's going to be great! Those guys are brilliant, and I love working with brilliant people.

Finally, if you're in the Esbjerg area, working with iOS, get in touch with me. If you'd love to start working with iOS, get in touch with me! There's an NSCoder Night coming up soon, biweekly I hope. :-)

My comments on the iPhone

Written by: | Posted on:

Having slept on it and digested a lot of articles, these are my comments on the iPhone announced yesterday:

  • It runs OS X. In my book that means a BSD platform. I'm looking forward to having this confirmed. I so miss having BSD on my mobile. :-)
  • WiFi - thank you
  • Cool browsing interface due to CoreAnimation - great! :-)
  • No UMTS/3G? Yes, we all know 3G is slow, but EDGE is way slower. What's up? I really hope the European version will sport 3G
  • 2MP camera? Come on, Apple, that is SO last year!! I thought Apple was supposed to set a standard other would come running after
  • Max 8GB disk? Ok, fair enough, but you already have that out on the market and have had it for a while. Look at Ritek & co, they just announced 16 and 32GB solid state discs
  • Why is it not possible to buy music on the run? When I'm over at my friends' place and we talk about music, I'd love to be able to get the tune right away. But it seems I can't buy it from iTunes. (I'm sure they'll fix this soon enough, though ;-) )
  • I must admit I'm skeptical towards the QWERTY keyboard on-screen with no tactile feedback, but I'm looking forward to giving it a spin and see what it does for me.
  • Google Maps is great! But I already have that on my Nokia 6280.

Further things I'd like to know: is there a camera connector for it? And if so, does the internal software support RAW?

Now, I'm cautious about one thing: warranty. Apple has a reputation to refuse to repair iPods that have been handled extremely nice. I don't handle stuff nice. My Ericsson mobile phone drowned when I took a dive in the ocean, not long after my Palm 3e took a fly through the air and landing on the floor in an awkward position after being out drinking. I figured I'd smack it all into one, and got the Sony/Ericsson P800 which got a dint in the screen a year after I got it. Figuring I'd only go with cheap stuff from now on, my Nokia 6280 has survived a few rides through the air with no problem. They are even making sports versions that are extra protected. I'm always doing something, always in action, and the stuff that I take along gets a trip trough the air occasionally. So, I'm really going to be looking at how fragile these phones will be. If they're not, I might just spend the $599 for one. Probably in its 2nd iteration, though

My take on the Apple TV

Written by: | Posted on:

The Apple TV is a device I have been looking forward to since the iTV prototype was announced. Why would I want this rather than a Mac Mini? Well.... my question is still unanswered. But these were my surprises and questions:

  • Question: Ethernet and Wifi, does this device work like an Airport Extreme as well? :-) The ethernet plug, is that gigabit ethernet or 100 mbit like the Airport Extreme? (why they didn't go for gigabit there beats me)
  • No DVD, No Blueray, No HD-DVD. Seriously, guys, I don't want to have to run to another room to load my DVD. And if I had a computer in my livingroom, I'd be using it instead of the Apple TV
  • 40 GB HDD is small. My 200GB disk with my iPhoto libraries and iTunes library is full and needs an upgrade. Add movies to this, and 40 GB is too small. On 40 GB you could squeeze in a single HDD quality movie (30GB) and a normal DVD quality movie (8 GB). Two movies and your system is full. One movie only in best quality. Why would I want this?
  • How is DivX support for this device coming along?
  • How do they intend to work out 5.1 surround with two analog sound outputs?
  • PVR - having a built in tuner and recording TV shows and storing it in iTunes, possibly syncing it with my mobile phone (iPhone perhaps some day) or iPod Video. A decent PVR system is really what I'm in the market for these days, and that's not the Apple TV.

My take so far is that the best Apple TV around so far is the Mac Mini. But I'm sure the concept is great, so I'm looking forward to future revisions. Having said that: the Apple TV has an USB slot. I wonder what they'll expect us to hook up there. Looks like an USB HUB, a 500GB HDD, an audio interface and a TV receiver so far. That'll become one expensive Apple TV with a lot of spaghetti cabling. Same with the Mini, though, but that's after all an entire computer

My favourite CD shop

Written by: | Posted on:

Well, in Oslo at least, is Aktiv Klassisk in Øvre Slottsgate 5, 0157 Oslo, Phone +47 2233 6080. In case you feel like buying me a CD some day, you really can't go wrong this place. And the staff are wonderfull

My Valentine

Written by: | Posted on:
My Valentine

I always fall for cellists. I love the sound of the cello. I love the shape of the cello. And look what the cello has to say on the subject. You'll notice that the last string is broken. The poor little thing, I felt like fixing it right away, but it wasn't mine and I'd probably make it worse

My project - Overtone analysis

Written by: | Posted on:

I think it's about time I introduce my project:

I want to use Pd to extract the overtones of the recorder and train a neural network to identify what kind of sound (broad, thin, glass-ish, etc) I'm playing. I want to use this to control VST processors to shape the sound I play. And after the network is trained, I want to the analysis and processing in real-time.

At the moment I'm reading up on alternatives to FFT to separate out overtones, and I've made a prototype as a proof-of-concept kind of thing using fiddle~ to identify the overtones in hz and bp~ to separate them out as audio streams. It still has lots of problems such as artifacts, sound degeneration and latency issues. But it gets the job done, so I'm optimistic.

I'd prefer to do my project as a part of a Ph.D, but since Ph.D funding takes a while to find, I'm already starting. Can't wait for formalities. :-) When I've checked that it is ok to release code here I'll post some as I progress.

Image Image

Father, husband, software developer, musician and photographer.

Get to know what I'm up to


© 2020 Niklas Saers Contact Me