Skip to content
Projects

lyft/Hammer has 709 GitHub stars and 40 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-15 02:31 UTC. Last push 2026-11-13.

How these counts are measured

Measured star growth

in 24h
0
in 7 days
Collecting history
in 15 days
Collecting history
in 1 month
Collecting history

Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.

About

iOS touch synthesis library

Developer Tools

README.md

Original

Hammer

If you can't touch this, it's Hammer time!

Demo

Hammer is a touch, stylus and keyboard synthesis library for emulating user interaction events. It enables better ways of triggering UI actions in unit tests, replicating a real world environment as much as possible.

  • Real events: touches and key presses go through UIKit like a user's, so gesture recognizers, controls and SwiftUI handle them as they would on a device.
  • Tests: tap, swipe, drag, pinch and type in XCTest or Swift Testing, finding views by accessibility identifier, label, value or traits.
  • Running apps: the hammer command line tool and AI agents can drive an app that runs Hammer's agent, see what's on screen and try view changes live.

⚠️ IMPORTANT: This library makes extensive use of private APIs and should never be included in a production app.

Installation

Hammer requires Swift 6.0 and iOS 17.0 or later. Add it with SwiftPM:

.package(url: "https://github.com/lyft/Hammer.git", from: "2.0.0")

Add the Hammer product to your test target, and HammerAgent to your app to drive it with the command line tool. CocoaPods is deprecated.

Writing tests

Hammer tests need a host application to send touches. Create an EventGenerator for the view, view controller, SwiftUI view or window you test, then send it events:

@MainActor
final class SignInTests: XCTestCase {
    func testSignIn() async throws {
        let eventGenerator = try await EventGenerator(viewController: SignInViewController())

        try await eventGenerator.fingerTap(at: "email_field")
        try await eventGenerator.keyType("[email protected]")
        try await eventGenerator.fingerTap(at: .label("Sign In", traits: .button))
        try await eventGenerator.waitUntilVisible("home_title")
    }
}

Locations can be an accessibility identifier, an AccessibilityQuery, a view or a point. A few more of what you can do:

try await eventGenerator.fingerSwipe(at: "list", direction: .up)
try await eventGenerator.fingerEdgeSwipe(direction: .right)
try await eventGenerator.fingerDrag(from: "card", to: "trash", duration: 0.5)
try await eventGenerator.fingerPinch(fromDistance: 100, toDistance: 50, duration: 0.5)
try await eventGenerator.keyPress(.returnOrEnter)
try await eventGenerator.waitUntilHittable("checkout_button")

Learn more:

Driving a running app

Start the agent in a debug build of your app. By default it only runs in the simulator and only accepts connections from the same Mac:

#if DEBUG
import HammerAgent

let agent = HammerAgent()
try await agent.start()
#endif

Install the prebuilt hammer tool from the latest release:

mkdir -p ~/.local/bin
curl -fsSL https://github.com/lyft/Hammer/releases/latest/download/hammer-macos.zip -o /tmp/hammer-macos.zip
unzip -o /tmp/hammer-macos.zip -d ~/.local/bin

Then see what's on screen and act on it:

hammer describe                      # Elements on screen, each with a ref such as e12
hammer tap --ref e12
hammer type-text --identifier email --text "[email protected]"
hammer wait-for --identifier home_title --condition visible
hammer screenshot --output screen.png
hammer help swipe                    # Arguments and examples of a command

To give an AI agent the same commands as tools, run hammer mcp as an MCP server. For example, with Claude Code:

claude mcp add hammer -- ~/.local/bin/hammer mcp

Learn more:

Documentation

Every guide is in docs.

License

Hammer is released under the Apache License. See LICENSE