Peekie
Swift package for parsing Xcode .xcresult files with support for XCTest and Swift Testing frameworks
Install / Use
/learn @dodobrands/PeekieREADME
Peekie
<p align="center"> <img width="128" height="128" alt="Peekie Logo" src="https://github.com/user-attachments/assets/df9d5117-ba56-465d-8607-96302e638f4e" /> </p>The PeekieSDK package provides a Swift module for parsing .xcresult files generated by Xcode to produce a structured report of build and test results. It supports both XCTest and Swift Testing frameworks, and works with the modern .xcresult format (without requiring the --legacy flag). It allows developers to programmatically access detailed information about test cases, code coverage, and warnings from their CI/CD pipelines or automated scripts.
Table of Contents
Features
- Supports XCTest and Swift Testing frameworks.
- Parses modern
.xcresultformat (usesxcresulttoolwithout--legacyflag). - Parses
.xcresultfiles to create a typed model of the test results and code coverage. - Parses build warnings from
.xcresultfiles and associates them with source files. - Separates test suite structure from coverage files: Test suites are identified by URLs (like
test://...) without file paths in.xcresult. Coverage data and warnings, however, include actual file paths. Therefore, test suites (Module.suites) and files with coverage/warnings (Module.files) are kept separate in the data model. - Filters out coverage data related to test helpers and test cases.
- Provides a detailed breakdown of modules, test suites, coverage files, and repeatable tests.
- Calculates total and average test durations, as well as combined test statuses.
- Supports identifying slow tests based on average duration.
- Includes utility functions for filtering tests based on status.
- Can be executed as a command-line tool to generate test reports directly from the terminal.
- SonarQube integration: Generates SonarQube Generic Test Execution XML format for CI/CD integration.
- JSON output: Generates structured JSON with full report data (tests, coverage, warnings) for machine consumption and
jqprocessing.
Installation
Command-Line Tool (Recommended)
The recommended way to install the peekie command-line tool is via mise:
mise use github:dodobrands/peekie
Swift Package
To use PeekieSDK in your Swift package, add it to the dependencies for your Package.swift file:
let package = Package(
name: "YourPackageName",
dependencies: [
.package(url: "https://github.com/dodobrands/Peekie.git", from: "4.0.0")
],
targets: [
.target(
name: "YourTargetName",
dependencies: ["PeekieSDK"]
)
]
)
Migration Guide
If you're upgrading from version 3.* (formerly DBXCResultParser), please see the Migration Guide for detailed instructions on how to migrate your code. The guide includes:
- Step-by-step migration instructions
- Code examples showing before/after changes
- Common migration patterns
- List of removed features and renamed types
Usage
Parsing xcresult Files
To parse an .xcresult file and access the report data, initialize a Report with the path to the .xcresult file:
import PeekieSDK
let xcresultPath = URL(fileURLWithPath: "/path/to/your.xcresult")
let report = try await Report(xcresultPath: xcresultPath)
// Optionally, you can control what data to include:
// Parse without coverage data (faster)
let reportWithoutCoverage = try await Report(
xcresultPath: xcresultPath,
includeCoverage: false
)
// Parse without warnings
let reportWithoutWarnings = try await Report(
xcresultPath: xcresultPath,
includeWarnings: false
)
// Access different parts of the report:
let modules = report.modules
let coverage = report.coverage // Coverage value from 0.0 to 1.0
// IMPORTANT: Test suites and coverage files are separated
// Test suites are identified by URLs (like test://...) without file paths in .xcresult.
// Coverage data and warnings include actual file paths.
// Therefore, test results are accessed via Module.suites, while coverage and warnings
// are accessed via Module.files.
// Iterate over modules, test suites, and tests:
for module in modules {
print("Module: \(module.name)")
// Access test suites with their test cases
for suite in module.suites {
print(" Suite: \(suite.name)")
for repeatableTest in suite.repeatableTests {
print(" Repeatable Test: \(repeatableTest.name)")
for test in repeatableTest.tests {
print(" Test: \(test.status.icon) - Duration: \(test.duration)")
}
}
}
// Access coverage files (separate from test suites)
for file in module.files {
print(" Coverage File: \(file.name)")
// Access warnings for this file
for warning in file.warnings {
print(" Warning: \(warning.message)")
}
if let coverage = file.coverage {
print(" Lines Covered: \(coverage.linesCovered)/\(coverage.linesTotal)")
}
}
}
Formatters
The PeekieSDK package provides multiple formatters to convert parsed .xcresult data into different output formats. Each formatter is designed for specific use cases:
- ListFormatter: Generates human-readable list output for terminal display and logs
- SonarFormatter: Generates SonarQube Generic Test Execution XML format for CI/CD integration
- JsonFormatter: Generates structured JSON output with full report data including tests, coverage, and warnings
ListFormatter
The ListFormatter class provides a way to format the data from a Report into a human-readable string. It outputs a detailed list of test results.
Usage
To format your test report data, create an instance of ListFormatter:
import PeekieSDK
// Assuming you have already created a `Report` instance as `report`
let report: Report = ...
// Create a list formatter
let formatter = ListFormatter()
// Format the report data into a string
let formattedOutput = formatter.format(report)
// Print the formatted output
print("Formatted Output:\n\(formattedOutput)")
The format method can also take an array of Report.Module.File.RepeatableTest.Test.Status to filter which test results are included in the output. By default, it includes all test statuses.
Filtering by status:
// Only show failures
let failuresOnly = formatter.format(report, include: [.failure])
// Show both failures and skipped tests
let failuresAndSkipped = formatter.format(report, include: [.failure, .skipped])
// Show only successful tests
let successesOnly = formatter.format(report, include: [.success])
Including device details:
By default, device information is filtered out from test names. When enabled, device names (e.g., [iPhone 15 Pro]) will be appended to test names if this information is present in the .xcresult file (typically when tests are run on multiple devices).
// Default: device details are always hidden
let output = formatter.format(report)
// Include device details if available in .xcresult
let outputWithDevices = formatter.format(report, includeDeviceDetails: true)
Example output:
includeDeviceDetails: false→test_example()includeDeviceDetails: true→test_example() [iPhone 15 Pro](if device info exists in .xcresult)
Output Format
Outputs a detailed list of test results, including the name of each test suite and the status of each test.
Basic Test Statuses:
✅- Success❌- Failure⏭️- Skipped🤡- Expected Failure⚠️- Mixed (flaky test with different results across retries)🤷- Unknown
Example output:
FileA.swift
✅ test_success()
❌ test_failure() (Failure message)
⏭️ test_skip() (Skip message)
🤡 test_expectedFailure() (Failure is expected)
⚠️ test_flacky() (Flacky failure message)
FileB.swift
✅ test_success()
Parameterized Tests (Swift Testing): Each argument from parameterized tests is displayed as a separate test line with its own status. The example below shows a regular test and two parameterized tests with different argument types:
CalculatorTests.swift
✅ testAddition()
✅ testMultiplication(factor:) (2)
✅ testMultiplication(factor:) (5)
❌ testDivision(dividend:divisor:) (10, 2)
✅ testDivision(dividend:divisor:) (20, 4)
SonarFormatter
The SonarFormatter class generates test execution reports in SonarQube Generic Test Execution XML format. This format is compatible with SonarQube's test execution import feature, allowing you to visualize test results directly in SonarQube.
Use cases:
- CI/CD pipeline integration with S
Related Skills
gh-issues
347.2kFetch GitHub issues, spawn sub-agents to implement fixes and open PRs, then monitor and address PR review comments. Usage: /gh-issues [owner/repo] [--label bug] [--limit 5] [--milestone v1.0] [--assignee @me] [--fork user/repo] [--watch] [--interval 5] [--reviews-only] [--cron] [--dry-run] [--model glm-5] [--notify-channel -1002381931352]
node-connect
347.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Writing Hookify Rules
108.0kThis skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
