Calabash-android: attach to running app

1.6k views Asked by At

I have calabash-android set up working perfectly with a default scenario (using cucumber to run tests or calabash-android console to enter REPL mode).

However, under some scenarios, it turns out to be pretty useful to be able to attach to an app that's already running. For instance, I would start an app in debug mode and start the tests to be able to set breakpoints and check why certain features don't work as expected in my scenarios.

When it comes to Calabash on iOS, this task is really straightforward: no additional preparation needed as the app starts with a test server bundled in and I can attach calabash to it at any time. However, Calabash Android seems to be force-quitting the app every time I try to start calabash having the app running.

Is there any way around it?

EDIT Looks like the below answers didn't help much, but I still hope someone (calabash devs, where are you?) will stumble upon this one day. I have spent some time discovering the issue myself, and that's what the specific issue is:

  1. Start the app in Debug mode (using Xamarin, for instance)
  2. Start calabash-android console PATH_TO_APK
  3. Try issuing any commands (e.g. query("*")) – it fails with a message KeepAliveDisconnected
  4. Try running start_test_server_in_background – the app is killed and debug session is terminated

Digging deeper into details, I found out that start_test_server_in_background in fact runs shell am instrument with sh.calaba.instrumentationbackend.CalabashInstrumentationTestRunner being instrumentation backend and a bunch of other flags describing which app to instrument, what port to use etc.

Thus being said, the following would help a lot: is it possible for shell am instrument to attach to a running app?

3

There are 3 answers

1
bunbun On BEST ANSWER

Great question, and the simple answer is:

No

At least not on Android (I cannot attest to iOS). Why? Calabash has to establish hooks on the app you want to run on before you can run any tests on the app. This is due to a mixture of reasons regarding the Android stack.

The first reason is security. Android locks down apps in the installation phase based on the permissions set for it. Because of this design, Calabash (or any other app-process-interfering script) will not be able to execute in the middle of an app process. As you have found out, you can still run Calabash tests together with the start of the app as Android will validate Calabash for this purpose.

The second reason is architecture. Android is designed as layers of processes and views. What you are trying to do will probably interfere with more than one process on a variety of levels.

The best you can do is start Calabash for an App without reinstalling it, but that is the most Android will allow you to do.

Finally, I apologize if this answer does not delve into the very technical details, these were the answers given to me during a particular Hackathon as I struggled with a similar issue.

3
Tobias On

Calabash-Android stops any test-server, and the app under test, when you start a new server on the same port.

If you wish to attach a console to a running test, simply open a console (bundle exec calabash console ..) and issue your gestures and queries, without starting the app using start_test_server_in_background. A common pattern is to use the gem pry, with the method binding.pry to pause the test, and launch a console.

Notice that the generated Calabash-Android cucumber skeleton will run shutdown_test_server automatically when a cucumber scenario fails or ends. You can remove that call and attach a console.

0
android.weasel On

I've just successfully done it. There wasn't much to it - I just paused the Calabash tests at the point of failure with an 'After' hook that pauses Ruby (actually, it uses IRB, but that's incidental):

After do |scenario|
  if scenario.failed? && scenario.source_tag_names.include?('@wip') && PLATFORM == ANDROID
    require 'irb'
    require 'irb/completion'
    ARGV.clear
    IRB.start
  end
end

then fired up Android Studio, clicked on the 'Attach debugger to Android process' button to the right of the normal debug icon in the toolbar, clicked the 'Can't connect to adb' pop-up to tell it to try again (without killing/restarting adb myself), clicked the process it offered me, and... it connected happily. I successfully set a breakpoint and hit it, and executed query("*") in the console both before and after.

I haven't had to change the Calabash instrument command to add -e 'debug true' or anything.

The only thing that went wrong was that Android Studio took out the adb server when I closed it, but I think that's a known bug^H^H^Hfeature.

Perhaps if you create a 'And Cucumber waits for a keypress' step that waits for you to hit the host computer's keyboard, so you can attach Android Studio to the phone's process and set your breakpoints before resuming. Obviously though - breakpoints are going to mess up any timing in the script.