Beginners Guide to Using Appium with NodeJs for Automation Testing of Android Applications
Android Automation Testing Using NodeJS
In this post, we learn Android automated testing using Appium with NodeJs. Appium is a freely distributed open source framework for mobile application UI testing. Appium supports all languages that have Selenium client libraries like Java, Objective-C, JavaScript with node.js, PHP, Ruby, Python, C# etc.
Prerequisites to use Appium:
- Android SDK (Android Studio with bundled SDK).
- JDK (Java Development Kit).
- Appium Client for Windows (client).
- IDE and testing framework of choice. In our case, we will use node.js and mocha testing frameworks, so we need to install js. Even though Appium client supplied with bundled “Node.exe” and NPM (node package manager), we will install those manually to have the latest version.
Appium installation on Windows
Step 1. Download and install JDK. After installation, you will need to set your “JAVA_HOME” environment variable. Do the following (on Windows 10):
- Go under “Settings” → “System” → “About”.
- Click the “System info”
- Click the “Advanced system settings”
- Click the “Environment Variables” button.
- Under “System variables” click the “New…” button, name variable as “JAVA_HOME”, set value to point at your jdk installation directory, for example “C:\Program Files\Java\jdk1.8.0_144” (without quotes) and click “OK”.
- Find the “Path” variable among “System variables”, select it and click “Edit…”. Click the “New…” and add the following line at the end “%JAVA_HOME%\bin” (without quotes).
- To verify everything is set up correctly, run Command Prompt (Win + R, type “cmd” and hit Enter) and type “java –version” (without quotes). If everything is okay, you should see the image below, if not, backtrack your steps once again.
Step 2. Download and install Android SDK. After installation, you will need to set the “ANDROID_HOME” environment variable. Process is identical to described above, with some exceptions:
2.1. When setting value for the “ANDROID_HOME” variable you should set it to point at your Android SDK folder, for example “C:\Users\zelri\AppData\Local\Android\sdk1” (without quotes). In case you aren’t able to locate the “AppData” folder under your user folder you may need to enable the “Show hidden folders” option. For Windows 10, go to the “View” tab of your user folder and check the “Hidden items” checkbox.
2.2. When modifying the “Path” variable you should add the following “%ANDROID_HOME%\platform-tools” (without quotes) to point at Android SDK.
Step 3. Download and install node.js. Just follow installation guidelines and that is it. Node.js should set environment variables required without your help, so typing “node –v” and “npm –v” in Command Prompt should give you current versions of node.js and NPM:
In case of installation errors, you may need to set it by yourself and point it to the installation folder, for example, “C:\Program Files\nodejs\” (without quotes).
Step 4. Install Appium client. Just follow installation guide and that is it.
Step 5. Run Appium client as administrator. You should see the following
Step 6. We will start Appium server on localhost (type “localhost” into “Host” with default port
Congratulations, now we have our Appium server up and running!
Now, let’s proceed with configuring test environment for running our tests.
Device setup for running the tests
Step 1. Start Android emulator of choice or attach a real device via USB cable.
The most comfortable way to run emulator is to run Android Studio, then go “Tools” → “Android” → “AVD Manager” and configure desired device.
Step 2. Open Command Prompt and navigate to your ANDROID_HOME directory, for instance “cd C:\Users\zelri\AppData\Local\Android\sdk1\platform-tools” (without quotes).
Step 3. Run “adb devices” to see the list of attached devices, both real and emulated.
Step 4. In current directory start android-debugging-bridge (adb) by typing and executing “adb start-server” command
Next, allow USB debugging on your device.
Step 5. Run “npm install appium-doctor –g” command to install command line tool called “appium-doctor” for verifying Appium installation for particular platform. This command will install this tool via NPM and make it available to use from everywhere.
Step 6. Run “appium-doctor –android” command to check that everything is ready to work. You should see the below output
Step 7. Now we want to install our application under test (AUT) on the device. In order to do this, we need to click the “Start new session” button in our running Appium client
Step 6. In order to install desired application on device, we need to fill in form on the “Desired Capabilities” tab with correct info, for example:
Here:
- platformName – either Android or iOS. In our case it is Android;
- platformVersion – version of OS on our device. For emulators, you have to set their version according to the “Target” column of AVD Manager. For real devices check their version by going to “Settings” → “About phone” → “Android version”;
- deviceName – name of your device. Even though this option is technically omitted in current version of Appium (1.6.5), it is required to start the session. Use an appropriate one from “adb devices” commands result.
- app – path to application we want to install. In my case, I’ve used a full path to .apk file of CALCU calculator for sake of this guide.
- fullReset – this option indicates whenever we want or not to rollback all actions were done after we’ve finished the session. Set to “false” because we want to install the app and use it after session ending.
Step 7. Click the “Start Session” button. You should see your app’s launch activity on your device screen. In case of CALCU, I’ve got this:
And now you should see the Appium inspector for your app
Writing tests
Now, our environment is set up and ready for further manipulations and tests. Let’s start with a project setup.
Step 1. Create a new folder and name it “CALCU node.js android test”.
Step 2. Navigate to your folder in a Command Prompt or start one directly in the folder.
Step 3. Execute the “npm init” command in the folder. Follow setup process in a command line to configure package.json file of your project.
Step 4. After the basic setup, we need to add a bunch of dependencies in order to make our tests work. We will use mocha as our testing framework with chai for assertions. Also, we will require webdriverio testing utility, which improves interaction with mobile web, native and hybrid apps. So, run the following commands:
- npm install appium-uiautomator2-driver
- npm install mocha
- npm install chai
- npm install chai-as-promised
- npm install wd
- npm install wdio-appium-service –D (–D parameter here stands for installation this dependency only for developers)
- npm install webdriverio –D
- npm install wdio-mocha-framework –D
Step 5. Create a subfolder and call it “helpers”. In “helpers” create a file with .js extension and name it “desiredCapabilities”. In this file we will specify all the necessary details for our script, such as application we want to run and device we want to use for testing. Here is the completed content of the file, which follows our previous steps:
Notes to remember here:
- automationName – name of automation driver, essential parameter for webdriverios locators to work.
- appPackage – it is the package of your application. If you are testing application from .apk file without developers support, you can obtain bundle id this way:
- in Command Prompt navigate to “build-tools” folder of your Android SDK home directory. In my case, I’m running “cd C:\Users\zelri\AppData\Local\Android\sdk1\build-tools\25.0.3”
- we will use AAPT (Android Asset Packaging Tool) to get appPackage and appActivity parameters from existing .apk. Run “aapt dump badging path/to/your.apk”. In case that didn’t work, try “./aapt dump badging path/to/your.apk”. Here is the appPackage:
And here is the appActivity:
Now, our desired capabilities are set and test knows what to do on launch.
Step 6. Return to the project folder and create a file “webriverio-calcu.js”. This will be our script to run. In order to locate elements, we will use mobile selectors, provided by webdriverio, for example:
client.click('android=new UiSelector().resourceId("com.candl.athena:id/digit5")')
This resource is specific to CALCU application. To get resource id of the element or any other available identifier we will use Appium Inspector. Just click the element while in the “Select” mod to properties panel to appear and grab the most suitable attribute or identifier. More usages of UiSelector class are available here
Step 7. With that in place, we are ready to start scripting. As I said earlier, we will use webdriverio for writing our test, so consider looking at their docs for more info.
7.1. Let’s import all the required components and create client – the main object for interactions and actions:
var webdriverio = require('webdriverio'); var expect = require('chai').expect; var config = require('./helpers/desiredCapabilities').options; var client = webdriverio.remote(config);
7.2. Now, create the main function by using describe keyword and pass “CALCU Testing” as the first parameter. This function will wrap our tests and declare before and afterEach hooks. Those will be executed before our test-suite and after each method respectively.
describe('CALCU Testing', function () { before(function () { this.timeout(50000); return client.init(); }); afterEach(function(){ this.timeout(5000); return client.click('android=new UiSelector().resourceId("com.candl.athena:id/clear")'); });
7.3. Create a sub-function by using describe keyword and call it “Test CALCU addition”. Set timeout for executing tests of this suite and write the tests with use of it keyword.
//addition testing describe("Test CALCU addition", function () { this.timeout(15000); it("test-close-startup-screen", function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/btn_close")'); }); it("test-two-positive-addition",function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/digit5")') .click('android=new UiSelector().resourceId("com.candl.athena:id/plus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit2")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.equal('7'); }); }); it("test-negative-positive-addition", function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/minus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit5")') .click('android=new UiSelector().resourceId("com.candl.athena:id/plus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit2")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.equal('-3'); }); }); it("test-negative-addition", function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/minus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit5")') .click('android=new UiSelector().resourceId("com.candl.athena:id/plus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/minus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit2")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.equal('-7'); }); }); });
7.4. Add a test group to cover multiplication functionality.
//multiplication testing describe("Test CALCU multiplication", function () { this.timeout(15000); it("test-positive-multiplication", function () { return client.click('android=new UiSelector().resourceId("com.candl.athena:id/digit5")') .click('android=new UiSelector().resourceId("com.candl.athena:id/mul")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit2")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.equal('10'); }); }); it("test-positive-negative-multiplication", function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/minus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit5")') .click('android=new UiSelector().resourceId("com.candl.athena:id/mul")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit2")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function(text){ console.log("Text we've got from output: ",text); expect(text).to.equal('-10'); }); }); it("test-negative-multiplication", function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/minus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit5")') .click('android=new UiSelector().resourceId("com.candl.athena:id/mul")') .click('android=new UiSelector().resourceId("com.candl.athena:id/minus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit2")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function(text){ console.log("Text we've got from output: ",text); expect(text).to.equal('10'); }); }); it("test-zero-multiplication", function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/digit5")') .click('android=new UiSelector().resourceId("com.candl.athena:id/mul")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit0")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function(text){ console.log("Text we've got from output: ",text); expect(text).to.equal('0'); }); }); });
7.5. Add a test group to test division operations.
//division testing describe("Test CALCU division", function () { this.timeout(15000); it("test-divide-even",function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/digit6")') .click('android=new UiSelector().resourceId("com.candl.athena:id/div")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit2")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.equal('3'); }); }); it("test-divide-odd",function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/digit7")') .click('android=new UiSelector().resourceId("com.candl.athena:id/div")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit3")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.include('2.333'); }); }); it("test-divide-positive-negative",function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/digit6")') .click('android=new UiSelector().resourceId("com.candl.athena:id/div")') .click('android=new UiSelector().resourceId("com.candl.athena:id/minus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit3")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.equal('-2'); }); }); it("test-divide-negative",function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/minus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit6")') .click('android=new UiSelector().resourceId("com.candl.athena:id/div")') .click('android=new UiSelector().resourceId("com.candl.athena:id/minus")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit3")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.equal('2'); }); }); it("test-divide-by-zero",function(){ return client.click('android=new UiSelector().resourceId("com.candl.athena:id/digit5")') .click('android=new UiSelector().resourceId("com.candl.athena:id/div")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit0")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.equal('Error'); }); }); });
7.6. Add some more advanced test, which involves swipe action, for example.
Here is an example:
//advanced testing describe("Test CALCU advanced", function(){ this.timeout(90000); it("test-",function(){ return client .swipeDown('android=new UiSelector().resourceId("com.candl.athena:id/pullview_root")',100,3) .click('android=new UiSelector().resourceId("com.candl.athena:id/custom_key_0")') .click('android=new UiSelector().resourceId("com.candl.athena:id/btn_trig_units")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit9")') .click('android=new UiSelector().resourceId("com.candl.athena:id/digit0")') .click('android=new UiSelector().resourceId("com.candl.athena:id/equal")') .element('android=new UiSelector().resourceId("com.candl.athena:id/display").childSelector(new UiSelector().className("android.widget.TextView"))') .getText() .then(function (text){ console.log("Text we've got from output: ",text); expect(text).to.equal('1'); }); }); })
7.7. In the scope of wrapper function, add after hook, which will close the connection as well as the AUT.
after(function() { return client.end(); }); });
Step 8. Open “package.json” and under scripts section add exactly the same line: “webdriverio-calcu”: “mocha webdriverio-calcu.js”. This will allow us to run our test by “npm run webriverio-calcu”.
Step 9. Finally, your “CALCU node.js android test” folder should be like this:
And your “helpers” folder must be like this:
Step 10. Close your Appium inspector by hitting the “Quit Session & Close Inspector” button at the top-center panel.
Step 11. Run script by executing “npm run webdriverio-calcu” in your project folder. You should see execution process on your device as good as mocha log in the console:
That’s it. Hope this post on Android automated testing using Appium with NodeJs is helpful to you. Now you are able to run your node.js scripts (supported by webdriverio, mocha and chai) via Appium to test your mobile apps.
About Author:
TestMatick company offers automation testing services for the web and mobile applications. With TestMatick you can also utilize all the advantages of continuous integration. It includes setup of the environment which automatically integrates all parts of a project and executes tests everytime when someone makes a commit to the version control. We provide QA automation services using the following automation tools:
– Selenium WebDriver
– Appium
– Automated QA TestComplete
– HP / Mercury QTP
– Segue SilkTest
– Ranorex
– Robotium