CargoLink Mobile
The mobile twin of the CargoLink web application, with the same three services, the same rates and the same twenty stock lines. Every rupee on the quote screen comes out of arithmetic printed on the page, so you assert on a number you worked out rather than the one the app happened to show you.
This application is for practice purpose, for automation testers.
| Application | CargoLink Mobile |
| Package | in.co.jstestingacademy.cargolink |
| First activity | .LoginActivity |
| Login | student / practice123 |
| Screens | 9 |
| Minimum Android | 7.0 (API 24) |
| Download | Download the APK (ZIP) – the zip holds the APK and a README |
| Access | Inside the Lifetime Membership – sign in first |
- Volumetric weight against actual weight, and the half-kilo rounding between them
- Four zone factors, each reachable with a pincode from the list on the screen
- A rate broken into nine labelled fields, not one sentence to parse
- A flat charge that appears only for an out-of-delivery-area pincode
- Insurance that is refused without a declared value
- A booking form that will not take the same phone number twice
- A seven-stage timeline you move along yourself, so you assert on a state you caused
- Twenty stock lines with search, two dropdowns, a filter and four sort orders
- Issuing more than is on hand – refused, with the number that is really there
- One item that starts at zero, so “out of stock” is there on the first run
Everything is held in memory, so closing the app is the reset. No server, no network, no leftovers from the last run.
The screens, and how to reach them
Every control carries a resource id and an accessibility description, so you can locate it either way. No XPath over the whole tree, and no counting positions.
.LoginActivitySign in
| Resource id | Appium locator |
|---|---|
login_username | AppiumBy.id("in.co.jstestingacademy.cargolink:id/login_username") |
login_password | AppiumBy.id("in.co.jstestingacademy.cargolink:id/login_password") |
login_remember | AppiumBy.id("in.co.jstestingacademy.cargolink:id/login_remember") |
login_submit | AppiumBy.id("in.co.jstestingacademy.cargolink:id/login_submit") |
login_error | AppiumBy.id("in.co.jstestingacademy.cargolink:id/login_error") |
login_go_register | AppiumBy.id("in.co.jstestingacademy.cargolink:id/login_go_register") |
login_fill_demo | AppiumBy.id("in.co.jstestingacademy.cargolink:id/login_fill_demo") |
.RegisterActivityCreate account
| Resource id | Appium locator |
|---|---|
register_full_name | AppiumBy.id("in.co.jstestingacademy.cargolink:id/register_full_name") |
register_username | AppiumBy.id("in.co.jstestingacademy.cargolink:id/register_username") |
register_email | AppiumBy.id("in.co.jstestingacademy.cargolink:id/register_email") |
register_phone | AppiumBy.id("in.co.jstestingacademy.cargolink:id/register_phone") |
register_password | AppiumBy.id("in.co.jstestingacademy.cargolink:id/register_password") |
register_confirm | AppiumBy.id("in.co.jstestingacademy.cargolink:id/register_confirm") |
register_terms | AppiumBy.id("in.co.jstestingacademy.cargolink:id/register_terms") |
register_error | AppiumBy.id("in.co.jstestingacademy.cargolink:id/register_error") |
register_submit | AppiumBy.id("in.co.jstestingacademy.cargolink:id/register_submit") |
.HomeActivityHome
| Resource id | Appium locator |
|---|---|
home_welcome | AppiumBy.id("in.co.jstestingacademy.cargolink:id/home_welcome") |
home_count | AppiumBy.id("in.co.jstestingacademy.cargolink:id/home_count") |
home_quote | AppiumBy.id("in.co.jstestingacademy.cargolink:id/home_quote") |
home_shipments | AppiumBy.id("in.co.jstestingacademy.cargolink:id/home_shipments") |
home_shipments_sub | AppiumBy.id("in.co.jstestingacademy.cargolink:id/home_shipments_sub") |
home_stock | AppiumBy.id("in.co.jstestingacademy.cargolink:id/home_stock") |
home_stock_sub | AppiumBy.id("in.co.jstestingacademy.cargolink:id/home_stock_sub") |
home_note | AppiumBy.id("in.co.jstestingacademy.cargolink:id/home_note") |
.QuoteActivityGet a quote
| Resource id | Appium locator |
|---|---|
quote_service | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_service") |
quote_from_pincode | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_from_pincode") |
quote_from_city | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_from_city") |
quote_to_pincode | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_to_pincode") |
quote_to_city | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_to_city") |
quote_weight | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_weight") |
quote_length | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_length") |
quote_width | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_width") |
quote_height | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_height") |
quote_declared | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_declared") |
quote_insured | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_insured") |
quote_cod | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_cod") |
quote_error | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_error") |
quote_calculate | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_calculate") |
quote_card | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_card") |
quote_volumetric | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_volumetric") |
quote_chargeable | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_chargeable") |
quote_zone | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_zone") |
quote_freight | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_freight") |
quote_fuel | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_fuel") |
quote_oda | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_oda") |
quote_insurance | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_insurance") |
quote_cod_fee | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_cod_fee") |
quote_gst | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_gst") |
quote_total | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_total") |
quote_book | AppiumBy.id("in.co.jstestingacademy.cargolink:id/quote_book") |
.BookActivityBook shipment
| Resource id | Appium locator |
|---|---|
book_route | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_route") |
book_service | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_service") |
book_total | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_total") |
book_sender | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_sender") |
book_sender_phone | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_sender_phone") |
book_receiver | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_receiver") |
book_receiver_phone | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_receiver_phone") |
book_goods | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_goods") |
book_date | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_date") |
book_terms | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_terms") |
book_error | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_error") |
book_confirm | AppiumBy.id("in.co.jstestingacademy.cargolink:id/book_confirm") |
.TrackActivityTrack shipment
| Resource id | Appium locator |
|---|---|
track_awb | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_awb") |
track_booked_note | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_booked_note") |
track_route | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_route") |
track_service | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_service") |
track_people | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_people") |
track_pickup | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_pickup") |
track_total | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_total") |
track_status | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_status") |
track_timeline | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_timeline") |
track_advance | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_advance") |
track_shipments | AppiumBy.id("in.co.jstestingacademy.cargolink:id/track_shipments") |
.ShipmentsActivityMy shipments
| Resource id | Appium locator |
|---|---|
shipments_search | AppiumBy.id("in.co.jstestingacademy.cargolink:id/shipments_search") |
shipments_find | AppiumBy.id("in.co.jstestingacademy.cargolink:id/shipments_find") |
shipments_count | AppiumBy.id("in.co.jstestingacademy.cargolink:id/shipments_count") |
shipments_empty | AppiumBy.id("in.co.jstestingacademy.cargolink:id/shipments_empty") |
shipments_list | AppiumBy.id("in.co.jstestingacademy.cargolink:id/shipments_list") |
shipment_awb | AppiumBy.id("in.co.jstestingacademy.cargolink:id/shipment_awb") |
shipment_route | AppiumBy.id("in.co.jstestingacademy.cargolink:id/shipment_route") |
shipment_detail | AppiumBy.id("in.co.jstestingacademy.cargolink:id/shipment_detail") |
shipment_status | AppiumBy.id("in.co.jstestingacademy.cargolink:id/shipment_status") |
.StockActivityWarehouse stock
| Resource id | Appium locator |
|---|---|
stock_search | AppiumBy.id("in.co.jstestingacademy.cargolink:id/stock_search") |
stock_category | AppiumBy.id("in.co.jstestingacademy.cargolink:id/stock_category") |
stock_warehouse | AppiumBy.id("in.co.jstestingacademy.cargolink:id/stock_warehouse") |
stock_sort | AppiumBy.id("in.co.jstestingacademy.cargolink:id/stock_sort") |
stock_below_reorder | AppiumBy.id("in.co.jstestingacademy.cargolink:id/stock_below_reorder") |
stock_count | AppiumBy.id("in.co.jstestingacademy.cargolink:id/stock_count") |
stock_empty | AppiumBy.id("in.co.jstestingacademy.cargolink:id/stock_empty") |
stock_list | AppiumBy.id("in.co.jstestingacademy.cargolink:id/stock_list") |
item_sku | AppiumBy.id("in.co.jstestingacademy.cargolink:id/item_sku") |
item_name | AppiumBy.id("in.co.jstestingacademy.cargolink:id/item_name") |
item_where | AppiumBy.id("in.co.jstestingacademy.cargolink:id/item_where") |
item_quantity | AppiumBy.id("in.co.jstestingacademy.cargolink:id/item_quantity") |
item_flag | AppiumBy.id("in.co.jstestingacademy.cargolink:id/item_flag") |
.StockActivityReceive or issue (dialog)
| Resource id | Appium locator |
|---|---|
move_item | AppiumBy.id("in.co.jstestingacademy.cargolink:id/move_item") |
move_on_hand | AppiumBy.id("in.co.jstestingacademy.cargolink:id/move_on_hand") |
move_quantity | AppiumBy.id("in.co.jstestingacademy.cargolink:id/move_quantity") |
move_error | AppiumBy.id("in.co.jstestingacademy.cargolink:id/move_error") |
How to practise on it
Eight steps, in order. Nothing here needs a server or test data — install it, point Appium at it, and start.
| 1. Set the device up | A phone or an emulator that adb devices can see. Turn on Developer options, then USB debugging. Android 7.0 or newer. |
| 2. Install the app | adb install jsta-shopkart.apk, or copy the file to the phone and open it. Allow installing from this source when Android asks. |
| 3. Start Appium | Appium 2 with the UiAutomator2 driver, started with the base path /wd/hub. Check it is up at http://127.0.0.1:4723/wd/hub/status. |
| 4. Point your test at the app | Set appPackage and appActivity from the table above. Nothing else is needed — no server, no seed data, no network. |
| 5. Find your first element | Use the resource id or the accessibility description from the screen tables below. Both work. Never locate by position: that is the habit this app exists to break. |
| 6. Sign in | Register your own account, or press Fill in the practice account and sign in as student / practice123. |
| 7. Work through the screens | Each one below lists what it is there to teach. Start with the simple ones and keep the awkward ones — the gestures, the long list, the WebView — for when the straightforward parts pass reliably. |
| 8. Check your work twice | Turn on Connect to the live API in Settings, do the same thing again, and read the record back through the API. If both agree, your test is checking something real. |
Where the data goes
The app has two modes and the switch is in its Settings. Offline is the default, because a classroom with no wifi still needs a working app and a suite that waits on a server is a slower suite.
| Offline (the default) | Everything the app creates is held in memory on the phone. No network, no server, no account on anybody’s database. Closing the app clears it, so every test run starts from the same place. |
| Online (Settings → Connect to the live API) | The same screens, on top of the practice API. Sign-up goes to POST /auth/register, sign-in to POST /auth/token, and what you create is stored against your account in {prefix}jsta_api_records. Read the very same records back in Postman. |
| The honest answer | |
|---|---|
| Where a practice account lives | {prefix}jsta_api_accounts – a table of its own, with the password hashed. Cleared after 30 days. |
| What it is not | It is not a WordPress user and not a customer. A practice sign-up never reaches wp_users, never creates a WooCommerce order, and cannot buy anything. Real sign-ups and real orders are a different part of the site entirely. |
| Where an order or an appointment lives | Offline: on the phone only. Online: {prefix}jsta_api_records, one row per record, scoped to your account. |
| The website’s own practice apps | The web versions at /qa-apps/ keep their data in the browser’s localStorage, so they reset when you clear site data. They never touch the server either. |
| Why registering is worth it | The shared student login is scoped to the token: sign in again and you start empty. Your own account is scoped to the account, so your records follow you to Postman, to a second phone, and to tomorrow. |
- Settings → Connect to the live API, then register and sign in.
- Do the thing in the app – place the order, book the appointment.
- Sign in to the practice API with the same account and read it back.
It is one record, reached two ways. That is how a UI test and an API test can check each other instead of each trusting itself.
Getting it onto a device
The short version of the steps above, for reference.
| 1. Download and unzip | The zip holds the .apk and a README with the package name and the login. |
| 2. Put it on the device | adb install jsta-shopkart.apk over USB, or copy the file to the phone and open it. Android will ask you to allow installing from this source – that is normal for any app that did not come from the Play Store. |
| 3. Start Appium | appium --base-path /wd/hub, with the UiAutomator2 driver installed. |
| 4. Point your test at it | Set appPackage and appActivity from the table above. Nothing else is needed: the apps hold their data in memory, so a restart is a clean fixture and no server has to be running. |