Introducing Hackpium, an Appium that can Run Multiple iOS Simulator in a Mac
An appium that can run multiple ios simulator in one mac.
First of all, I’m not the only one who finished this project. I work side by side, not like batman-robin, but more like batman-batman side by side with my colleague, Rezi Rusnadiputra.
Around 2 weeks ago I created a post about setting multiple iOS device with appium, in that post I said we still working the magic to run multiple iOS simulators in one mac, and here we are, we finished the trick and we’re going to reveal its secret.
Appium
Appium state they don’t support multiple iOS simulator. The reason is appium use xcode command to install and run the test. We need to wait another release and hope they already support multiple iOS simulators, or until xcode can support multiple iOS simulators, I’ve heard about fbsimctl, a tool that can spawn multiple iOS simulator in one mac. I and Rezi decided to change all of xcode related code in appium, and change it into fbsimctl.
Appium has bundles of library that help it to run xcuitest, e.g. node-simctl that handle simulator control, appium-ios-simulator that handle opening and anything related with directory-specified manipulation things, and appium-xcuitest-driver the one that handle our most important thing in iOS testing with appium, xctest.
All of those library written in nodejs, and has a test to make sure our code is working. After some research conducted, We decided to hack node-simctl first because it handle all of simulator-related in appium. If you need to look at the repository, click every title which related on appium below.
node-simctl
We fork node-simctl from appium, right after it, we found a pull request from steve gray, he want to use fbsimctl instead of xcrun command which exactly what we need to hack appium. We also add screenshot capabilities, which has not been implemented by steve gray. Screenshot capabilities is used in appium desktop inspector.
When this library is finished, we integrate it to appium and we found that appium still using open command to boot the simulators. As we predicted we still can not launch the second simulator. We search for the library that tells appium to use open command, and we found appium-ios-simulator is the library that handle it, also appium-ios-simulator kills booted simulator every time when we start appium.
appium-ios-simulator
We change open command that boot iOS simulator to fbsimctl boot, we also bypass killAllSimulator function to keep our simulator up and running. We don’t do anything much in this library, we need to make sure we can spawn multiple simulator at one mac.
At this state we already can open two simulator, but we still can not run our test with appium. It will kill one of spawned simulator because appium use xcodebuild in running webdriveragent, and appium-xcuitest-driver is the library that handle it.
appium-xcuitest-driver
This is the hardest part in creating hackpium. This library has any conditions, and we need to be sure where should we add fbsimctl, because we don’t want to break any functionality of this library.
The first thing we try is changing how appium run the webdriveragent test. Webdriveragent is a bridge between the phone/simulator and the appium command. If we don’t have webdriveragent we can not run our test with appium (correct me if iI’m wrong).
Appium use xcodebuild build-for-testing test-without-building command to run webdriveragent test. Since we can not build webdriveragent using fbsimctl, because it kills one of our simulators. We decided to run webdriveragent test with fbsimctl.
./fbsimctl [udid]
launch_xctest [path]/WebDriverAgentRunner.xctest
com.apple.mobilesafari --port 8100 -- \
listen
We can get the [path] after we build webdriveragentrunner. I and Rezi decided to included the build folder in our appium-xcuitest-driver to make it easier to implement.
Appium checks the webdriveragent server to verify webdriveragent is up and running. Appium treat simulator and real device differently, when using real device it’ll check the port that we specify, but in simulator appium only check port 8100, even though we already specify which port we want to use. Because of it appium will hit the same port, and our other simulator can not be used. With this information we put a same treatment either in real device or simulator.
The last problem we‘ve known is appium will uninstall-install, and try to run webdriveragent if it can’t create a session. We can’t treat it with appium way because uninstall and installing require us to use xcrun. We find another way to fix this problem. We’re going to shutdown-boot the simulator to clear the session. As far as we use hackpium it solve the problem, but if you find this broke, or you find another way to solve it. You could reach me and Rezi.
Pros and cons
Our hackpium has it own pros and cons. The pros is obviously we can run multiple simulator in one mac, it saves us costs to buy another mac. or resource to run another mac in virtual machine.
The cons is we need to build manually the WebDriverAgentRunner to run hackpium. The reason is because we don’t found any library that can do multiple build, and its feature is exactly the same with xcode command.
Hackpium also support android tests, but we haven’t try it with iOS devices. I also can not predict is it running on iOS device or not, since we bypass some of xcode-related code to prevent it to kill another simulator.
How to install it
You need to install brew first, to install fbsimctl. You could install brew with this command.
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
- Clone our hackpium in this repository
- The third, run ./setup script in that script we install all the dependencies, including fbsimctl, and hackpium.
How to use it
First thing first is building webdriveragent in the simulator. The easiest way to do it is using appium desktop, and start a new session with it. It’ll automatically build, and install webdriveragent. You could close this appium server after webdriveragent is installed.
If you already do it run this command to use our custom appium
$ hackpium -p <PORT>
it also has exactly the same desired capabilities that appium has, but to run hackpium, you need to include this capabilities
prebuildWDA=true
wdaLocalPort=<WebDriverAgentPort>
hackpium will not run if you don’t set prebuildWDA argument to true. Because we add all of what we do in appium-xcuitest-driver under the condition of prebuildWDA equals true. The last but not least, this is the footage. We have succesfully run hackpium with robotframework. If you already try it and having any issues, I and Rezi are all ears.