playwright-ussd
v0.1.0
Published
Playwright-based framework for testing real USSD flows -- single-shot codes and interactive multi-step menus alike -- against a physical Android device.
Downloads
184
Maintainers
Readme
playwright-ussd
Test USSD codes from Playwright, against a real Android device.
USSD (the *123#-style codes used for mobile money, airtime, and carrier
menus) has no browser and no standard testing API. This package drives the
same on-screen prompt a person sees when dialing a code, so you can write
ordinary Playwright tests against it — single-shot codes and multi-step
menus alike.
Install
npm install --save-dev playwright-ussd @playwright/testRequirements
- A physical Android device with an active SIM, connected over USB
adbavailable on yourPATH- Node.js 18+
The device screen needs to be unlockable without a PIN, pattern, or password. Dialing a code always wakes the screen and clears the keyguard first, which only works without a secure lock set.
If more than one device is connected, set ANDROID_SERIAL to target a
specific one.
Usage
import { test, expect, dialStep, replyStep } from "playwright-ussd/fixture";
test("balance check", async ({ ussd }) => {
const screen = await dialStep(ussd, "*123#");
expect(screen.isFinal).toBe(true);
expect(screen.text).toContain("Balance");
});
test("menu navigation", async ({ ussd }) => {
const menu = await dialStep(ussd, "*100#");
expect(menu.text).toContain("Send Money");
const submenu = await replyStep(ussd, "1", "Send Money");
expect(submenu.text).toContain("Enter recipient number");
});The ussd fixture gives each test a fresh session and closes it
automatically when the test ends. dialStep/replyStep are optional
wrappers around ussd.dial()/ussd.reply() that record each call as a
named Playwright step with the response logged — useful for reports, but
you can call the session methods directly if you'd rather not have the
extra step nesting:
import { test, expect } from "playwright-ussd/fixture";
test("balance check", async ({ ussd }) => {
const screen = await ussd.dial("*123#");
expect(screen.text).toContain("Balance");
});Your project also needs a playwright.config.ts. Since there's no browser
involved, keep workers: 1 (only one USSD session can be active on a
device at a time) and skip the projects field entirely:
import { defineConfig } from "@playwright/test";
export default defineConfig({
testDir: "./tests",
workers: 1,
});API
UssdSession (import { UssdSession } from "playwright-ussd")
| Method | Returns | Description |
|---|---|---|
| dial(code) | Promise<{ text, isFinal }> | Dials the code, returns the first screen |
| reply(text) | Promise<{ text, isFinal }> | Sends a reply to an open menu, returns the next screen |
| cancel() | void | Ends an open session; does nothing if it already ended |
| .history | UssdScreen[] | Every screen seen so far, in order |
text is the raw response shown on screen. isFinal is true once the
session has ended — there's nothing left to reply to at that point, and
calling reply() will throw.
How it works
Dialing a code sends it as a normal phone call
(android.intent.action.CALL), which Android intercepts as USSD instead of
placing a real call. The response shows up in a system dialog, which this
package reads and drives with adb shell uiautomator dump and
adb shell input.
There's a public Android API for this too
(TelephonyManager.sendUssdRequest), but it only supports a single
response and can't be used for menus that need a reply — the telephony
stack receives that response internally but has no way to hand it back
through that API. Reading the on-screen dialog directly works for both
cases, since it's the same path the built-in dialer itself uses.
Limitations
- No emulator support — USSD requires a real SIM and carrier signaling.
- The dialog is matched by resource-id, which can vary slightly across
Android versions and OEM skins. If a device isn't recognized, run
adb shell uiautomator dumpwhile a USSD dialog is open and compare the ids against whatUssdSessionlooks for insrc/ussdSession.ts. - Only one session can run at a time per device.
License
MIT
