June 14, 2020

Creating a sms otp reader to run sms based tests on cloud devices

By chandan

Problem Statement

Our Krdivo Mobile application has integration with multiple eCommerce providers such as Tokopedia and Shoppee, now to connect to these providers app to app is quite difficult as these merchants need SMS OTP verification before you can perform any action on their app.

In local environment, we can use the real device with real Simcard to get SMS and read SMS from notification panel but when we run tests on cloud devices using cloud services such as BrowserStack and Soucelabs then we face two problems-

1. These devices don’t have sim cards so we can’t receive OTP SMS
2. Devices are not dedicated so every time we run our tests a random device from the pool of devices is selected so we can’t set up everything on the device once and then reuse set up later.

Solution-

So how can we solve this? On a high level, it was pretty much clear we can’t ignore these tests as these tests are one of the most critical cases in our app and we can’t test them daily on our local environment with every new change made in merchant code.

Requirements for achieving this-

1.One cloud-based virtual sim card service which can provide incoming SMS data in API(preferred way) or in HTML/text(secondary option).

2. Virtual sim card service should support the Indonesian number as we need to log in using the Indonesian number on the merchant app.

3. Provide at least 20 incoming SMS to cater to our automated tests at least twice in our regression test run.

4. Service should be within our budget(not more than 200k IDR~15$ or less).


How did I achieve this?

I start looking for an API/service that can give me a virtual Indonesian phone number which can provide incoming SMS data in JSON/HTML/text format and data can be fetched through API/web service call as fetching data from UI would be time-consuming and may require IP whitelisting from SMS providers.

I looked at the number of APIs such as Twilio and Plivo, I had used them in Drishtisoft to simulate outgoing and incoming calls in my webrtc automation suite.

But the problem was –

(i)They did not offer incoming SMS functionality on virtual phone numbers
(ii)They did not offer Indonesian numbers
(iii) If they satisfied above two conditions then price was really high(for example Telkomsel)

Finally, After going into the various darker side of the internet and after trying out more than10 services(many services were fake too), I found the desired service –GoSMSGateway

They had their API in form param and they were using PHP as their server-side language. So my task was –

(i) Login into the service using my API credentials
(ii)Extracting the first unread SMS from list of SMS using the inbox
(iii)Archive all the SMS present on inbox so that state is clean once new tests try to read something from inbox

I logged in using their API, got content in HTML response, parsed content using jsoup, and then extracted otp using regex.

Code snippets are present below-

Response response1 = given().spec(gosmsspec).when().formParam("username", "youruser")
				.formParam("password", "yourpassword").post("/loginapi");
inboxHtml = response1.getBody().asString();
Document doc = Jsoup.parse(inboxHtml);
otp = doc.getElementsByClass("msg from").get(0).toString().replaceAll("[^0-9]", "").substring(0,3);
//^0-9 will remove all non numeric values and substring 0,3 will give first 4 characters from result(as otp is the first numeric word in sms but it may contain date also sometimes).

using session-id obtained from response1 and .delete(“api/sms/inbox/archieve”) , I deleted the inbox SMS list .

And that’s how our SMS OTP based tests are also running daily to make sure nothing is broken on merchant end in case of any change in merchant code.

Things to remember while doing this-

1. Do not run login based tests on merchant multiple times else your number may be blocked (try to run 1 or 2 times a day only).

2. If your tests have retry mechanism then customize it for OTP based tests.

3. Sometimes receiving OTP may take time so using retry with await to make sure, the performance of the test is not impacted.

Have questions? leave it in comments.