hs-mock API

hs_mock

A mock of the Hammerspoon hs global for testing Spoons under busted.

hs_mock.new() returns a fresh hs and the ctl test controls. The mock is strict: reading an hs.<name> it doesn’t provide raises hs_mock: hs.<name> is not mocked; tests can add or replace anything.

Mocked: logger; timer (doAfter, doEvery, new, secondsSinceEpoch, absoluteTime); task; menubar; notify; caffeinate.watcher; application (find, get, watcher, launchOrFocus, launchOrFocusByBundleID, frontmostApplication); hotkey.bind; audiodevice; image (imageFromName, iconForFile); execute; open; ipc (present); alert; settings; screen.mainScreen; mouse.absolutePosition; eventtap (keyStroke, leftClick, new, event); websocket; wifi; host.interfaceStyle; distributednotifications; spoons.resourcePath (returns the file unchanged); json.read, write; fs.attributes, mkdir; and Hammerspoon’s own fnutils and inspect, vendored. Event constants match Hammerspoon 1.1.1. json.read and json.write copy, like real serialization.

new

function hs_mock.new()
  -> hs: table
  2. ctl: HsMockCtl

Builds a fresh mock; call it from before_each.

return hs — The mock hs global; assign it to _G.hs.

return ctl — The test controls.

HsMockCtl

Test controls returned by hs_mock.new().

activate

function HsMockCtl.activate(notification: table, activationType: integer)

Activates a notification with a hs.notify.activationTypes value and calls its callback.

addAudioDevice

function HsMockCtl.addAudioDevice(attributes: { name: string, uid: string, input: boolean, transport: string, muted: boolean, volume: number, inUse: boolean })
  -> device: table

Adds an audio device: an output, or an input with input = true; uid defaults to name.

advance

function HsMockCtl.advance(seconds: number)

Moves the clock, firing due timers in due-time order (ties in scheduling order); doEvery and started hs.timer.new timers re-arm.

alerts

{ id: string, text: string, style: table, screen: table, seconds: number, closed: boolean }[]

One entry per hs.alert.show, which returns the string id.

appEvent

function HsMockCtl.appEvent(name: string, event: integer, app?: table)

Delivers a hs.application.watcher event to the started watchers.

appWatchers

table[]

Watchers from hs.application.watcher.new.

apps

table<string, table>

Apps hs.application.find and get return: by key, else by bundleID() among these and frontmost.

audio

{ outputs: table[], inputs: table[], defaultOutput: table, defaultInput: table }

Audio devices and defaults; setDefault*Device() updates the defaults.

audioEvent

function HsMockCtl.audioEvent(event: string)

Fires the running hs.audiodevice.watcher callback.

caffeinate

function HsMockCtl.caffeinate(event: integer)

Delivers a hs.caffeinate.watcher event to the started watchers.

caffeinateWatchers

table[]

Watchers from hs.caffeinate.watcher.new.

clicks

{ x: number, y: number }[]

Points passed to hs.eventtap.leftClick.

deviceEvent

function HsMockCtl.deviceEvent(device: table, event: string, scope: string, element: integer)

Calls a device’s watcher callback, if it is watching.

dirs

table<string, boolean>

Directories made by hs.fs.mkdir.

distributedNotification

function HsMockCtl.distributedNotification(name: string, object?: any, userInfo?: table)

Delivers a notification to running watchers registered for its name, or for all.

executed

string[]

Commands passed to hs.execute.

files

table<string, any>

The files behind hs.json and hs.fs; a non-table value reads as malformed JSON.

flush

function HsMockCtl.flush()

Fires the one-shot timers pending now, whatever their delay, moving the clock to each; leaves repeating timers and ones scheduled meanwhile.

frontmost

table?

What hs.application.frontmostApplication returns.

hotkeys

{ mods: string[], key: string, message: string, pressed: function, released: function, repeated: function, enabled: boolean, deleted: boolean }[]

Bindings made with hs.hotkey.bind.

images

table<string, any>

What hs.image.imageFromName / iconForFile return; unknown names give nil, as in Hammerspoon.

interfaceStyle

string?

What hs.host.interfaceStyle returns: nil (light) or "Dark", as macOS reports.

keyStrokes

{ mods: string[], key: string, delay: number, app: table }[]

Calls to hs.eventtap.keyStroke.

launched

string[]

Names and bundle ids passed to launchOrFocus / launchOrFocusByBundleID.

logged

function HsMockCtl.logged(level: "debug"|"error"|"info"|"verbose"|"warning")
  -> string[]

The messages logged at one level.

level:
    | "error"
    | "warning"
    | "info"
    | "debug"
    | "verbose"

logs

{ logger: string, level: string, message: string }[]

Every log line at every level.

HsMockMenubar[]

Menu bar items created by hs.menubar.new.

mousePosition

{ x: number, y: number }

What hs.mouse.absolutePosition reads and sets.

newEvent

function HsMockCtl.newEvent(attributes: { type: integer, systemKey: { key: string, down: boolean }, flags: table })
  -> event: table

Builds an event, as hs.eventtap.event constructors would.

notificationWatchers

table[]

Watchers from hs.distributednotifications.new.

notifications

table[]

Notifications from hs.notify.new, keeping _attributes, _sent and _withdrawn.

now

number

Virtual clock in seconds; drives hs.timer.secondsSinceEpoch and absoluteTime (integer nanoseconds).

onExecute

(fun(command: string, withUserEnv?: boolean):string, boolean, string, integer)?

Answers hs.execute; the default returns "", true, "exit", 0.

onTask

fun(task: HsMockTask):integer?, string?, string??

Called on task:start(); returning an exit code completes the task at once.

opened

string[]

Paths passed to hs.open.

posted

table[]

Events posted with event:post().

screenFrame

{ x: number, y: number, w: number, h: number }

What hs.screen.mainScreen():frame() returns (a copy).

settings

table<string, any>

Backing store for hs.settings.

tapEvent

function HsMockCtl.tapEvent(event: table)
  -> answer: any

Delivers an event to the first enabled tap watching its type.

return answer — What that tap’s callback returned, or nil if none matched.

taps

table[]

Event taps from hs.eventtap.new.

tasks

HsMockTask[]

Tasks created by hs.task.new.

timers

function HsMockCtl.timers()
  -> table[]

The running timers, in creation order.

websocketEvent

function HsMockCtl.websocketEvent(ws: table, event: string, message?: any)

Calls a socket’s callback.

websockets

table[]

Sockets from hs.websocket.new, keeping _url, _sent and _closed.

wifiEvent

function HsMockCtl.wifiEvent(message?: string, interface?: string)

Notifies the running wifi watchers.

param message — Defaults to "SSIDChange".

param interface — Defaults to "en0".

wifiNetwork

string?

What hs.wifi.currentNetwork returns.

wifiWatchers

table[]

Watchers from hs.wifi.watcher.new.

HsMockTask

A task from hs.task.new, keeping _path, _args, _running and _terminated.

_running

boolean

_terminated

boolean

closeInput

(method) HsMockTask:closeInput()
  -> HsMockTask

complete

(method) HsMockTask:complete(exitCode: integer, stdout?: string, stderr?: string)

Finishes the task and calls its callback, as the process exiting would.

param stdout — Defaults to "".

param stderr — Defaults to "".

isRunning

(method) HsMockTask:isRunning()
  -> boolean

pid

(method) HsMockTask:pid()
  -> unknown

start

(method) HsMockTask:start()
  -> HsMockTask

terminate

(method) HsMockTask:terminate()
  -> HsMockTask

HsMockMenubar

A menu bar item from hs.menubar.new; state set through its methods is kept in _title, _icon, _iconTemplate, _menu, _tooltip, _autosaveName, _inMenuBar and _deleted.

_autosaveName

any

_click

(method) HsMockMenubar:_click()

Calls the click callback, as clicking the menu bar item would.

_clickCallback

any

_deleted

boolean

_icon

any

_iconTemplate

any

_inMenuBar

boolean
any

_title

any

_tooltip

any

autosaveName

(method) HsMockMenubar:autosaveName(name: any)
  -> HsMockMenubar

delete

(method) HsMockMenubar:delete()

frame

(method) HsMockMenubar:frame()
  -> table

isInMenuBar

(method) HsMockMenubar:isInMenuBar()
  -> boolean

removeFromMenuBar

(method) HsMockMenubar:removeFromMenuBar()
  -> HsMockMenubar

returnToMenuBar

(method) HsMockMenubar:returnToMenuBar()
  -> HsMockMenubar

setClickCallback

(method) HsMockMenubar:setClickCallback(fn: any)
  -> HsMockMenubar

setIcon

(method) HsMockMenubar:setIcon(icon: any, template: any)
  -> HsMockMenubar

setMenu

(method) HsMockMenubar:setMenu(menu: any)
  -> HsMockMenubar

setTitle

(method) HsMockMenubar:setTitle(title: any)
  -> HsMockMenubar

setTooltip

(method) HsMockMenubar:setTooltip(tooltip: any)
  -> HsMockMenubar

title

(method) HsMockMenubar:title()
  -> unknown