Mobile tests that feel
like web tests.
Tapsmith is a test framework for native iOS and Android. We took the parts of Playwright that engineers love: the locators, the auto‑waiting, the trace viewer, and rebuilt them for real devices.
import { test, expect } from "tapsmith"
test("user can complete checkout", async ({ device }) => {
await device.getByRole("button", { name: "Add to cart" }).tap()
await device.getByText("Checkout").tap()
// mock the payment API
await device.route("**/api/payment", async (route) => {
await route.fulfill({ json: { status: "success" } })
})
await expect(device.getByText("Order Confirmed")).toBeVisible()
})
Tapsmith in 2 minutes: UI mode, the selector playground, multi-device tests, the MCP server, and the trace viewer.
The pain you're used to, gone.
Read the guide →Mock the network without a mock server.
In every other framework, mocking an API means a separate mock server, a proxy with certificate fiddling, or a special build of your app. In Tapsmith it’s device.route("**/api/payment", r => r.fulfill({ json })). One line, inline, done.
A real language, not a YAML ceiling.
Maestro flows are brilliantly simple, right up until the suite grows and logic ends up scattered across YAML, env-var parameters, and runScript snippets. Tapsmith tests are plain TypeScript: extract helpers, loop over fixtures, share setup between tests, and refactor with autocomplete and type-checking behind you.
Replay the failure, don’t reconstruct it.
Every run records a trace: every tap, every network call, every frame. When a test fails at 3 am, open the trace viewer and scrub through it like a video instead of staring at a stack trace.
Set up in minutes, not sprints.
Appium means a server, a driver per platform, a capabilities blob, and keeping all three in step with every Xcode and Android release. Tapsmith is one npm package: the daemon, the device agents and the trace viewer come with it, tapsmith init writes your config, and tapsmith doctor tells you what’s missing. No server to start, no drivers to update.
We've all tried the others.
This is a snapshot, not a sales pitch. Every tool in this list does something well; we just think the table tilts our way for most teams shipping consumer mobile apps in 2026.
✓ supported ◐ partial / via plugin — not available last verified Sep 2026
An API you can guess your way through.
// Same readable API across platforms
await device.getByRole("button", { name: "Sign in" }).tap()
await device.getByLabel("Email").type("[email protected]")
await device.getByText("Forgot password?").tap() // Mock any HTTP/HTTPS call, no proxy setup
await device.route("**/api/feed", route =>
route.fulfill({ json: fixtures.emptyFeed })
)
await device.route("**/payment", route => route.abort()) // Precise gesture control
await device.swipe("left")
await device.getByRole("image").pinchOut({ scale: 2 })
await device.getByLabel("Reorder").dragTo(device.getByText("Pinned")) See exactly what happened, and when.
Trace viewer
Every test run records a full trace. Scrub through a timeline of screenshots, see every tap and gesture overlaid on the screen, inspect every network request and response. When a test fails in CI, download the trace and replay it locally. No guessing, no "works on my machine."
npx tapsmith show-trace trace.zip UI mode
A browser-based interactive runner. Click any test to run it, see results stream in live, browse traces and screenshots inline, and mirror the device screen, all without leaving the browser.
npx tapsmith test --ui Spend the rest of the afternoon on something more interesting.
Install Tapsmith, point it at your app, and write your first test in five minutes.