flowdeck test
Run unit and UI tests.
# After 'flowdeck config set', run tests with saved settings
flowdeck test
# Run all tests (without config set)
flowdeck test -w MyApp.xcworkspace -s MyScheme -S "iPhone 16"
# Run tests on macOS
flowdeck test -D "My Mac"
# Run specific tests with --only
flowdeck test --only MyTests/LoginTests
flowdeck test --only MyTests/LoginTests/testLogin
flowdeck test --only "MyTests/Login Tests/test Login Success"
# Skip specific tests
flowdeck test --skip MyTests/SlowTests
flowdeck test --skip MyTests/IntegrationTests
# Multiple test targets
flowdeck test --test-targets "UnitTests,IntegrationTests"
# Run a specific test plan (name or path)
flowdeck test --plan "Smoke"
flowdeck test --plan "TestPlans/Smoke.xctestplan"
# Output modes
flowdeck test # Summary only (default)
flowdeck test -v # Verbose xcodebuild output
flowdeck test --progress # Show pass/fail as tests complete
flowdeck test --streaming # Clean output for file capture
flowdeck test --json # JSON for CI/automation
# Pass arguments to xcodebuild
flowdeck test --xcodebuild-options='-parallel-testing-enabled YES'
flowdeck test --xcodebuild-options='-enableCodeCoverage YES'
flowdeck test --xcodebuild-options='-resultBundlePath /tmp/results.xcresult'
flowdeck test --xcodebuild-env='CI=true'
# Show usage examples
flowdeck test --examples
Options
| Option | Short | Description |
|---|
--examples | | Show usage examples |
--project <path> | -p | Project directory |
--workspace <path> | -w | Path to workspace (.xcworkspace) or project (.xcodeproj) |
--scheme <name> | -s | Scheme name |
--configuration <name> | -C | Build configuration (Debug/Release) |
--simulator <name> | -S | Simulator name/UDID (REQUIRED for iOS/tvOS/watchOS) |
--device <name> | -D | Device name/UDID (use “My Mac” for macOS) |
--derived-data-path <path> | -d | Derived data path (default: ~/Library/Developer/FlowDeck/DerivedData) |
--config <path> | -c | Path to JSON config file with project settings |
--test-targets <targets> | | Specific test targets to run (comma-separated) |
--test-cases <cases> | | Specific test cases to run (comma-separated, format: TargetName/ClassName/testMethod) |
--only <tests> | | Run only specific tests (format: TargetName/ClassName or TargetName/ClassName/testMethod) |
--skip <tests> | | Skip specific tests (format: TargetName/ClassName or TargetName/ClassName/testMethod) |
--plan <name-or-path> | | Test plan name or .xctestplan path |
--json | -j | Output as JSON |
--verbose | -v | Show raw xcodebuild test output (beautified) |
--progress | | Show test results as they complete (pass/fail per test) |
--streaming | | Stream clean formatted test results (no escape codes, for file capture) |
--xcodebuild-options <args> | | Extra xcodebuild arguments (e.g., --xcodebuild-options='-parallel-testing-enabled YES') |
--xcodebuild-env <vars> | | Xcodebuild environment variables (e.g., ‘CI=true’) |
After running flowdeck config set, workspace, scheme, and simulator are saved to project state.
CLI parameters are only required if you haven’t run flowdeck config set, or to override saved values.
Use --device "My Mac" for macOS builds.
Test Filtering
The --only option supports multiple formats:
- Full path:
MyAppTests/LoginTests/testValidLogin - runs a specific test method
- Class name:
LoginTests - runs all tests in that class
- Method name:
testValidLogin - runs all tests with that method name (across classes)
You can specify multiple tests by using --only multiple times or separating with commas.
The --config parameter accepts a JSON file with portable project settings:
{
"workspace": "MyApp.xcworkspace",
"scheme": "MyApp",
"configuration": "Debug",
"platform": "iOS",
"version": "18.0",
"derivedDataPath": "/custom/path"
}
For macOS builds, set platform to "macOS" (no simulator needed).
JSON Output
When using --json, the command outputs newline-delimited JSON events during execution, followed by a final test result:
{"type":"status","stage":"COMPILING","message":"Building for testing..."}
{"type":"status","stage":"TESTING","message":"Running tests on iPhone 16..."}
{"type":"test_started","testName":"LoginTests/testValidLogin"}
{"type":"test_passed","testName":"LoginTests/testValidLogin","duration":0.023}
{"type":"test_failed","testName":"LoginTests/testInvalidLogin","duration":0.045,"reason":"XCTAssertEqual failed","file":"LoginTests.swift","line":42}
{"type":"result","success":false,"operation":"test"}
Event Types:
| Type | Description |
|---|
status | Progress updates with stage and message |
test_started | Test execution started with testName |
test_passed | Test passed with testName and duration |
test_failed | Test failed with testName, duration, reason, file, line |
test_skipped | Test skipped with testName and optional reason |
result | Final result with success and operation |
Final Result (Success):
{
"success": true,
"totalTests": 42,
"passedTests": 42,
"failedTests": 0,
"skippedTests": 0,
"duration": 12.5,
"passedTestNames": ["LoginTests/testValidLogin", "..."],
"skippedTestNames": [],
"failures": []
}
Final Result (Failure):
{
"success": false,
"totalTests": 42,
"passedTests": 40,
"failedTests": 2,
"skippedTests": 0,
"duration": 15.3,
"passedTestNames": ["..."],
"skippedTestNames": [],
"failures": [
{
"testName": "LoginTests/testInvalidLogin",
"reason": "XCTAssertEqual failed: (\"expected\") is not equal to (\"actual\")",
"fileName": "LoginTests.swift",
"lineNumber": 42,
"duration": 0.045
}
]
}
flowdeck test discover
Discover all available tests in a project by parsing test source files. This uses static source analysis (like Xcode’s Test Navigator) and does not require building the project.
# After 'flowdeck config set', discover tests with saved settings
flowdeck test discover
# Discover tests (without config set)
flowdeck test discover -w MyApp.xcworkspace -s MyScheme
# Output as JSON (for tooling)
flowdeck test discover --json
# Filter tests by name
flowdeck test discover --filter Login
flowdeck test discover -F Login
# Include tests that are skipped in the scheme or test plan
flowdeck test discover --include-skipped-tests
Options
| Option | Short | Description |
|---|
--project <path> | -p | Project directory |
--workspace <path> | -w | Path to workspace (.xcworkspace) or project (.xcodeproj) (also accepts --ws) |
--scheme <name> | -s | Scheme name (also accepts --sch) |
--config <path> | -c | Path to JSON config file with project settings (also accepts --cfg) |
--filter <query> | -F | Filter tests by name (case-insensitive) |
--json | -j | Output as JSON |
--include-skipped-tests | | Include tests that are skipped in the scheme or test plan (marked as skipped) |
--examples | -e | Show usage examples |
Test discovery uses static source parsing and doesn’t require building. It finds XCTestCase subclasses, test* methods, @Suite structs, and @Test functions directly from source files. By default, tests that are disabled in the scheme or test plan are excluded from results.
JSON Output
{
"tests": [
{
"target": "MyAppTests",
"class": "LoginTests",
"method": "testValidLogin",
"identifier": "MyAppTests/LoginTests/testValidLogin",
"file": "LoginTests.swift",
"filePath": "/path/to/LoginTests.swift",
"lineNumber": 15,
"isSkipped": false
}
]
}
flowdeck test plans
List test plans referenced by a scheme. This reads the scheme file and does not build the project.
# After 'flowdeck config set', list plans with saved settings
flowdeck test plans
# List plans (without config set)
flowdeck test plans -w MyApp.xcworkspace -s MyScheme
# Output as JSON (for tooling)
flowdeck test plans --json
Options
| Option | Short | Description |
|---|
--project <path> | -p | Project directory |
--workspace <path> | -w | Path to workspace (.xcworkspace) or project (.xcodeproj) (also accepts --ws) |
--scheme <name> | -s | Scheme name (also accepts --sch) |
--config <path> | -c | Path to JSON config file with project settings (also accepts --cfg) |
--json | -j | Output as JSON |
--examples | -e | Show usage examples |
JSON Output
{
"plans": [
{
"name": "Smoke",
"reference": "container:App/TestPlans/Smoke.xctestplan",
"path": "/path/to/App/TestPlans/Smoke.xctestplan",
"isDefault": true,
"isMissing": false
}
]
}