# Swift Testing — XCUITest, Test Plans y Cobertura

## XCUITest — UI Testing

```swift
class FacturasUITests: XCTestCase {

    var app: XCUIApplication!

    override func setUpWithError() throws {
        continueAfterFailure = false
        app = XCUIApplication()
        app.launchArguments = ["--ui-testing"]  // activa datos de prueba en la app
        app.launch()
    }

    func test_crearFactura_aparece_enLista() throws {
        // Navegar a crear
        app.navigationBars.buttons["Agregar"].tap()

        // Llenar formulario
        let campoFolio = app.textFields["folio"]
        campoFolio.tap()
        campoFolio.typeText("F-999")

        // Guardar
        app.buttons["Guardar"].tap()

        // Verificar en lista (waitForExistence para operaciones async)
        XCTAssertTrue(app.cells.staticTexts["F-999"].waitForExistence(timeout: 5))
    }

    func test_eliminar_factura_con_swipe() throws {
        // Asumir que hay al menos una factura en la lista
        let primeraCelda = app.cells.firstMatch
        XCTAssertTrue(primeraCelda.waitForExistence(timeout: 3))

        primeraCelda.swipeLeft()
        app.buttons["Eliminar"].tap()

        // Confirmar alerta si aparece
        if app.alerts.firstMatch.exists {
            app.alerts.buttons["Confirmar"].tap()
        }

        XCTAssertFalse(primeraCelda.exists)
    }
}
```

### Accessibility Identifiers para XCUITest

```swift
// En la Vista — usar accessibilityIdentifier para queries estables
TextField("Folio", text: $folio)
    .accessibilityIdentifier("folio")

Button("Guardar") { guardar() }
    .accessibilityIdentifier("boton-guardar")

// En el test
let campo = app.textFields["folio"]
let boton = app.buttons["boton-guardar"]
```

---

## Test Plans en Xcode

```json
// FacturasTestPlan.xctestplan
{
  "configurations": [
    {
      "id": "unit",
      "name": "Unit Tests",
      "options": {
        "codeCoverageEnabled": true,
        "codeCoverageTargets": ["MiApp"]
      }
    },
    {
      "id": "integration",
      "name": "Integration Tests",
      "options": {
        "environmentVariableEntries": [
          { "key": "API_URL", "value": "http://localhost:8080" },
          { "key": "USE_TEST_DATA", "value": "1" }
        ]
      }
    },
    {
      "id": "ui",
      "name": "UI Tests",
      "options": {
        "language": "es",
        "region": "MX"
      }
    }
  ],
  "testTargets": [
    { "target": { "name": "MiAppTests" }, "selectedTests": ["unit"] },
    { "target": { "name": "MiAppUITests" }, "selectedTests": ["ui"] }
  ]
}
```

---

## Cobertura en CI (Xcode + fastlane)

```ruby
# Fastfile
lane :test do
  run_tests(
    scheme: "MiApp",
    code_coverage: true,
    minimum_coverage_percentage: 80.0,
    output_types: "html,junit",
    result_bundle: true,
    xcargs: "-testPlan FacturasTestPlan"
  )
end

lane :snapshot_tests do
  run_tests(
    scheme: "MiApp",
    only_testing: ["MiAppTests/SnapshotTests"]
  )
end
```

```bash
# Desde línea de comandos
xcodebuild test \
  -scheme MiApp \
  -testPlan FacturasTestPlan \
  -enableCodeCoverage YES \
  -resultBundlePath TestResults.xcresult

# Generar reporte de cobertura
xcrun xccov view --report TestResults.xcresult
```
