Strategies for testing code that depends on the Amp SDK.
Unit Tests (Mocked)
Since the SDK shells out to the Amp CLI, unit tests should not call the real CLI. Instead, test your code's handling of the SDK's return values.
Testing with Known Responses
defmodule MyApp.AmpClientTest do
use ExUnit.Case, async: true
alias AmpSdk.Types.{ResultMessage, ErrorResultMessage}
test "handles successful result" do
result = %ResultMessage{
result: "All tests pass",
duration_ms: 2000,
num_turns: 1,
is_error: false
}
assert result.result =~ "tests pass"
end
test "handles error result" do
error = %ErrorResultMessage{
error: "Permission denied",
duration_ms: 100,
is_error: true,
permission_denials: ["Bash"]
}
assert error.is_error
assert "Bash" in error.permission_denials
end
endFor management JSON fixtures such as permissions_list/0 and mcp_list/0,
assert both the typed fields and the preserved extra payload so future CLI
fields remain non-breaking.
Testing Message Parsing
test "parses JSON line into typed struct" do
json = Jason.encode!(%{
type: "result",
subtype: "success",
session_id: "T-123",
is_error: false,
result: "done",
duration_ms: 500,
num_turns: 1
})
assert {:ok, %AmpSdk.Types.ResultMessage{result: "done"}} =
AmpSdk.Types.parse_stream_message(json)
endIntegration Tests (Live)
Tag live tests with @tag :live and exclude them by default. SSH-backed smoke
tests should use a separate :live_ssh tag so local live CLI coverage and
remote transport coverage can be run independently:
# test/test_helper.exs
ExUnit.start(exclude: [:live, :live_ssh])defmodule MyApp.AmpLiveTest do
use ExUnit.Case, async: false
@moduletag :live
@tag timeout: 60_000
test "executes a real prompt" do
assert {:ok, result} = AmpSdk.run(
"Reply with only: hello",
%AmpSdk.Types.Options{dangerously_allow_all: true}
)
assert String.contains?(String.downcase(result), "hello")
end
endRun live tests:
mix test --include live
Run live SSH smoke tests with the shared core harness:
CLI_SUBPROCESS_CORE_LIVE_SSH=1 \
CLI_SUBPROCESS_CORE_LIVE_SSH_DESTINATION=<ssh-host> \
mix test --only live_ssh --include live_ssh
Those tests no longer skip when the remote amp binary is absent. They assert
either a successful remote run or a structured :cli_not_found / :auth_error
result so error-shape regressions stay covered.
Testing Argument Building
The AmpSdk.Stream.build_args/1 function is public for testing:
test "builds correct CLI args" do
args = AmpSdk.Stream.build_args(%AmpSdk.Types.Options{
mode: "smart",
visibility: "private",
labels: ["ci"]
})
assert "--execute" in args
assert "--stream-json" in args
assert "--mode" in args
assert "--label" in args
endSDK Test Suite
# Run unit tests (mocked, fast)
mix test
# Run all tests including live CLI tests
mix test --include live