Token导航 LogoToken导航TokenDH.com
前端设计需要联网github未标认证来源可访问clear审计异常

axiom-xctest-automationaxiom xctest 自动化

Agent Skill

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑;涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

总安装

4,774

周安装

195

GitHub Stars

873

下载量

1,544
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:axiom-xctest-automation(axiom xctest 自动化)
来源仓库:https://github.com/charleswiltgen/axiom
仓库路径:skills/axiom-xctest-automation
安装命令:
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-xctest-automation
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-xctest-automation

简介

用于辅助测试设计、自动化测试、用例整理和回归验证,适合编写单元测试、端到端测试或根据失败日志定位问题。

  • 专注于 XCUITest UI 测试模式,强调稳定的元素标识、条件等待和测试隔离。
  • 通过 npx skills add 命令从指定 GitHub 仓库安装,需结合项目测试框架和运行命令使用。
  • 涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境,避免为了通过测试而改坏真实逻辑。
  • axiom-xctest-automation 属于前端设计类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

XCUITest Automation Patterns

Comprehensive guide to writing reliable, maintainable UI tests with XCUITest.

Core Principle

Reliable UI tests require three things:

  1. Stable element identification (accessibilityIdentifier)
  2. Condition-based waiting (never hardcoded sleep)
  3. Clean test isolation (no shared state)

Element Identification

The Accessibility Identifier Pattern

ALWAYS use accessibilityIdentifier for test-critical elements.

// SwiftUI
Button("Login") { ... }
    .accessibilityIdentifier("loginButton")

TextField("Email", text: $email)
    .accessibilityIdentifier("emailTextField")

// UIKit
loginButton.accessibilityIdentifier = "loginButton"
emailTextField.accessibilityIdentifier = "emailTextField"

Query Selection Guidelines

From WWDC 2025-344 "Recording UI Automation":

  1. Localized strings change → Use accessibilityIdentifier instead
  2. Deeply nested views → Use shortest possible query
  3. Dynamic content → Use generic query or identifier
// BAD - Fragile queries
app.buttons["Login"]  // Breaks with localization
app.tables.cells.element(boundBy: 0).buttons.firstMatch  // Too specific

// GOOD - Stable queries
app.buttons["loginButton"]  // Uses identifier
app.tables.cells.containing(.staticText, identifier: "itemTitle").firstMatch

Waiting Strategies

Never Use sleep()

// BAD - Hardcoded wait
sleep(5)
XCTAssertTrue(app.buttons["submit"].exists)

// GOOD - Condition-based wait
let submitButton = app.buttons["submit"]
XCTAssertTrue(submitButton.waitForExistence(timeout: 5))

Wait Patterns

// Wait for element to appear
func waitForElement(_ element: XCUIElement, timeout: TimeInterval = 10) -> Bool {
    element.waitForExistence(timeout: timeout)
}

// Wait for element to disappear
func waitForElementToDisappear(_ element: XCUIElement, timeout: TimeInterval = 10) -> Bool {
    let predicate = NSPredicate(format: "exists == false")
    let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element)
    let result = XCTWaiter.wait(for: [expectation], timeout: timeout)
    return result == .completed
}

// Wait for element to be hittable (visible AND enabled)
func waitForElementHittable(_ element: XCUIElement, timeout: TimeInterval = 10) -> Bool {
    let predicate = NSPredicate(format: "isHittable == true")
    let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element)
    let result = XCTWaiter.wait(for: [expectation], timeout: timeout)
    return result == .completed
}

// Wait for text to appear anywhere
func waitForText(_ text: String, timeout: TimeInterval = 10) -> Bool {
    app.staticTexts[text].waitForExistence(timeout: timeout)
}

Async Operations

// Wait for network response
func waitForNetworkResponse() {
    let loadingIndicator = app.activityIndicators["loadingIndicator"]

    // Wait for loading to start
    _ = loadingIndicator.waitForExistence(timeout: 5)

    // Wait for loading to finish
    _ = waitForElementToDisappear(loadingIndicator, timeout: 30)
}

Test Structure

Setup and Teardown

class LoginTests: XCTestCase {
    var app: XCUIApplication!

    override func setUpWithError() throws {
        continueAfterFailure = false
        app = XCUIApplication()

        // Reset app state for clean test
        app.launchArguments = ["--uitesting", "--reset-state"]
        app.launchEnvironment = ["DISABLE_ANIMATIONS": "1"]
        app.launch()
    }

    override func tearDownWithError() throws {
        // Capture screenshot on failure
        if testRun?.failureCount ?? 0 > 0 {
            let screenshot = XCUIScreen.main.screenshot()
            let attachment = XCTAttachment(screenshot: screenshot)
            attachment.name = "Failure Screenshot"
            attachment.lifetime = .keepAlways
            add(attachment)
        }
        app.terminate()
    }
}

Test Method Pattern

func testLoginWithValidCredentials() throws {
    // ARRANGE - Navigate to login screen
    let loginButton = app.buttons["showLoginButton"]
    XCTAssertTrue(loginButton.waitForExistence(timeout: 5))
    loginButton.tap()

    // ACT - Enter credentials and submit
    let emailField = app.textFields["emailTextField"]
    XCTAssertTrue(emailField.waitForExistence(timeout: 5))
    emailField.tap()
    emailField.typeText("user@example.com")

    let passwordField = app.secureTextFields["passwordTextField"]
    passwordField.tap()
    passwordField.typeText("password123")

    app.buttons["loginSubmitButton"].tap()

    // ASSERT - Verify successful login
    let welcomeLabel = app.staticTexts["welcomeLabel"]
    XCTAssertTrue(welcomeLabel.waitForExistence(timeout: 10))
    XCTAssertTrue(welcomeLabel.label.contains("Welcome"))
}

Common Interactions

Text Input

// Clear and type
let textField = app.textFields["emailTextField"]
textField.tap()
textField.clearText()  // Custom extension
textField.typeText("new@email.com")

// Extension to clear text
extension XCUIElement {
    func clearText() {
        guard let stringValue = value as? String else { return }
        tap()
        let deleteString = String(repeating: XCUIKeyboardKey.delete.rawValue, count: stringValue.count)
        typeText(deleteString)
    }
}

Scrolling

// Scroll until element is visible
func scrollToElement(_ element: XCUIElement, in scrollView: XCUIElement) {
    while !element.isHittable {
        scrollView.swipeUp()
    }
}

// Scroll to specific element
let targetCell = app.tables.cells["targetItem"]
let table = app.tables.firstMatch
scrollToElement(targetCell, in: table)
targetCell.tap()

Alerts and Sheets

// Handle system alert
addUIInterruptionMonitor(withDescription: "Permission Alert") { alert in
    if alert.buttons["Allow"].exists {
        alert.buttons["Allow"].tap()
        return true
    }
    return false
}
app.tap() // Trigger the monitor

// Handle app alert
let alert = app.alerts["Error"]
if alert.waitForExistence(timeout: 5) {
    alert.buttons["OK"].tap()
}

Keyboard Dismissal

// Dismiss keyboard
if app.keyboards.count > 0 {
    app.toolbars.buttons["Done"].tap()
    // Or tap outside
    // app.tap()
}

Test Plans

Multi-Configuration Testing

Test plans allow running the same tests with different configurations:

<!-- TestPlan.xctestplan -->
{
  "configurations" : [
    {
      "name" : "English",
      "options" : {
        "language" : "en",
        "region" : "US"
      }
    },
    {
      "name" : "Spanish",
      "options" : {
        "language" : "es",
        "region" : "ES"
      }
    },
    {
      "name" : "Dark Mode",
      "options" : {
        "userInterfaceStyle" : "dark"
      }
    }
  ],
  "testTargets" : [
    {
      "target" : {
        "containerPath" : "container:MyApp.xcodeproj",
        "identifier" : "MyAppUITests",
        "name" : "MyAppUITests"
      }
    }
  ]
}

Running with Test Plan

xcodebuild test \
  -scheme "MyApp" \
  -testPlan "MyTestPlan" \
  -destination "platform=iOS Simulator,name=iPhone 16" \
  -resultBundlePath /tmp/results.xcresult

CI/CD Integration

Parallel Test Execution

xcodebuild test \
  -scheme "MyAppUITests" \
  -destination "platform=iOS Simulator,name=iPhone 16" \
  -parallel-testing-enabled YES \
  -maximum-parallel-test-targets 4 \
  -resultBundlePath /tmp/results.xcresult

Retry Failed Tests

xcodebuild test \
  -scheme "MyAppUITests" \
  -destination "platform=iOS Simulator,name=iPhone 16" \
  -retry-tests-on-failure \
  -test-iterations 3 \
  -resultBundlePath /tmp/results.xcresult

Code Coverage

xcodebuild test \
  -scheme "MyAppUITests" \
  -destination "platform=iOS Simulator,name=iPhone 16" \
  -enableCodeCoverage YES \
  -resultBundlePath /tmp/results.xcresult

# Export coverage report
xcrun xcresulttool export coverage \
  --path /tmp/results.xcresult \
  --output-path /tmp/coverage

Debugging Failed Tests

Capture Screenshots

// Manual screenshot capture
let screenshot = app.screenshot()
let attachment = XCTAttachment(screenshot: screenshot)
attachment.name = "Before Login"
attachment.lifetime = .keepAlways
add(attachment)

Capture Videos

Enable in test plan or scheme:

"systemAttachmentLifetime" : "keepAlways",
"userAttachmentLifetime" : "keepAlways"

Print Element Hierarchy

// Debug: Print all elements
print(app.debugDescription)

// Debug: Print specific container
print(app.tables.firstMatch.debugDescription)

Anti-Patterns to Avoid

1. Hardcoded Delays

// BAD
sleep(5)
button.tap()

// GOOD
XCTAssertTrue(button.waitForExistence(timeout: 5))
button.tap()

2. Index-Based Queries

// BAD - Breaks if order changes
app.tables.cells.element(boundBy: 0)

// GOOD - Uses identifier
app.tables.cells["firstItem"]

3. Shared State Between Tests

// BAD - Tests depend on order
func test1_CreateItem() { ... }
func test2_EditItem() { ... }  // Depends on test1

// GOOD - Independent tests
func testCreateItem() {
    // Creates own item
}
func testEditItem() {
    // Creates item, then edits
}

4. Testing Implementation Details

// BAD - Tests internal structure
XCTAssertEqual(app.tables.cells.count, 10)

// GOOD - Tests user-visible behavior
XCTAssertTrue(app.staticTexts["10 items"].exists)

Recording UI Automation (Xcode 26+)

From WWDC 2025-344:

  1. Record — Record interactions in Xcode (Debug → Record UI Automation)
  2. Replay — Run across devices/languages/configurations via test plans
  3. Review — Watch video recordings in test report

Enhancing Recorded Code

// RECORDED (may be fragile)
app.buttons["Login"].tap()

// ENHANCED (stable)
let loginButton = app.buttons["loginButton"]
XCTAssertTrue(loginButton.waitForExistence(timeout: 5))
loginButton.tap()

Resources

WWDC: 2025-344, 2024-10206, 2023-10175, 2019-413

Docs: /xctest/xcuiapplication, /xctest/xcuielement, /xctest/xcuielementquery

Skills: axiom-ui-testing, axiom-swift-testing

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Claude Code

30.76%
按下载量换算475

OpenCode

24.84%
按下载量换算384

Codex

17.91%
按下载量换算277

Antigravity

12.39%
按下载量换算191

Cursor

7.21%
按下载量换算111

Gemini CLI

3.54%
按下载量换算55

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

未通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。

来源信息

继续浏览同类 Skills