Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion .github/workflows/sdk-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,51 @@ jobs:
VIZZLY_COMMIT_MESSAGE: ${{ github.event.pull_request.head.commit.message || github.event.head_commit.message }}
VIZZLY_COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.event.head_commit.id }}

# Swift SDK
swift:
name: Swift SDK
runs-on: macos-latest
timeout-minutes: 10

steps:
- uses: actions/checkout@v4

- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'

- name: Install CLI dependencies
run: npm ci

- name: Build CLI
run: npm run build

- name: Build Swift package
working-directory: ./clients/swift
run: swift build

- name: Run E2E tests (TDD mode)
working-directory: ./clients/swift
run: ../../bin/vizzly.js tdd run "VIZZLY_E2E=1 swift test --filter VizzlyE2ETests"
env:
CI: true

- name: Run E2E tests (Cloud mode)
working-directory: ./clients/swift
run: ../../bin/vizzly.js run "VIZZLY_E2E=1 swift test --filter VizzlyE2ETests"
env:
CI: true
VIZZLY_TOKEN: ${{ secrets.VIZZLY_SWIFT_CLIENT_TOKEN }}
VIZZLY_COMMIT_MESSAGE: ${{ github.event.pull_request.head.commit.message || github.event.head_commit.message }}
VIZZLY_COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.event.head_commit.id }}

# Status check for branch protection
check:
name: E2E Status
runs-on: ubuntu-latest
needs: [core-js, vitest, storybook, static-site, ember, ruby]
needs: [core-js, vitest, storybook, static-site, ember, ruby, swift]
if: always()
steps:
- name: Check all SDK E2E tests passed
Expand Down Expand Up @@ -409,4 +449,8 @@ jobs:
echo "Ruby SDK E2E tests failed"
exit 1
fi
if [[ "${{ needs.swift.result }}" == "failure" ]]; then
echo "Swift SDK E2E tests failed"
exit 1
fi
echo "All SDK E2E tests passed"
5 changes: 2 additions & 3 deletions clients/swift/Example/ExampleUITests.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import XCTest
import Vizzly
import VizzlyXCTest

/// Example UI tests demonstrating Vizzly integration
///
Expand Down Expand Up @@ -133,15 +134,13 @@ final class ExampleUITests: XCTestCase {
func testResponsiveLayout() throws {
// Test different device orientations
XCUIDevice.shared.orientation = .portrait
sleep(1) // Wait for orientation change

app.vizzlyScreenshot(
name: "home-portrait",
properties: ["orientation": "portrait"]
)

XCUIDevice.shared.orientation = .landscapeLeft
sleep(1)

app.vizzlyScreenshot(
name: "home-landscape",
Expand Down Expand Up @@ -187,7 +186,7 @@ final class ExampleUITests: XCTestCase {
// MARK: - Custom Threshold Example

func testWithCustomThreshold() throws {
// Allow up to 5% pixel difference
// Allow a higher comparison threshold for animated content
app.vizzlyScreenshot(
name: "animation-test",
threshold: 5,
Expand Down
12 changes: 8 additions & 4 deletions clients/swift/INTEGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ In Xcode:
1. **File → Add Package Dependencies**
2. Enter URL: `https://github.com/vizzly-testing/cli`
3. Select version/branch
4. **Important**: Add the package to your **UI Test target** (not the main app target)
4. Add the `VizzlyXCTest` product to your **UI Test target**

Use the core `Vizzly` product directly only when you need to send PNG data from
app or test-support code without the XCTest convenience extensions.

#### Option B: Local Package

Expand Down Expand Up @@ -78,6 +81,7 @@ Create or update your UI test file:
```swift
import XCTest
import Vizzly
import VizzlyXCTest

final class MyAppUITests: XCTestCase {

Expand Down Expand Up @@ -265,13 +269,13 @@ For views with animations or timing-sensitive content:
func testAnimatedView() {
app.launch()

// Wait for animation to complete
sleep(1) // Or use expectations
let finishedState = app.otherElements["AnimatedBannerReady"]
XCTAssertTrue(finishedState.waitForExistence(timeout: 5))

// Use threshold for slight variations
app.vizzlyScreenshot(
name: "animated-banner",
threshold: 5 // Allow 5% difference
threshold: 5
)
}
```
Expand Down
9 changes: 9 additions & 0 deletions clients/swift/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,22 @@ let package = Package(
.library(
name: "Vizzly",
targets: ["Vizzly"]),
.library(
name: "VizzlyXCTest",
targets: ["VizzlyXCTest"]),
],
targets: [
.target(
name: "Vizzly",
dependencies: []),
.target(
name: "VizzlyXCTest",
dependencies: ["Vizzly"]),
.testTarget(
name: "VizzlyTests",
dependencies: ["Vizzly", "VizzlyXCTest"]),
.testTarget(
name: "VizzlyE2ETests",
dependencies: ["Vizzly"]),
]
)
5 changes: 3 additions & 2 deletions clients/swift/QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ npm install -g @vizzly-testing/cli
1. Open your iOS project in Xcode
2. **File → Add Package Dependencies**
3. Paste: `https://github.com/vizzly-testing/cli`
4. Add to your **UI Test target** (not main app)
4. Add the `VizzlyXCTest` product to your **UI Test target**

## 3. Start TDD Server

Expand All @@ -28,6 +28,7 @@ vizzly tdd start
```swift
import XCTest
import Vizzly
import VizzlyXCTest

class MyAppUITests: XCTestCase {
let app = XCUIApplication()
Expand Down Expand Up @@ -96,7 +97,7 @@ button.vizzlyScreenshot(name: "submit-button")
### Custom Threshold

```swift
// Allow 5% pixel difference (useful for animations)
// Allow a higher comparison threshold for animated content
app.vizzlyScreenshot(
name: "animated-view",
threshold: 5
Expand Down
60 changes: 45 additions & 15 deletions clients/swift/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Unlike tools that render components in isolation, Vizzly captures screenshots di
## Features

- **Zero Configuration** - Auto-discovers Vizzly TDD server
- **Native XCTest Integration** - Simple extensions for `XCUIApplication` and `XCUIElement`
- **Native XCTest Integration** - Simple extensions for `XCUIApplication` and `XCUIElement` via the `VizzlyXCTest` helper product
- **iOS & macOS Support** - Works on both platforms
- **Automatic Metadata** - Captures device, screen size, and platform info
- **TDD Mode** - Local visual testing with instant feedback
Expand All @@ -22,21 +22,29 @@ Add Vizzly to your test target using Xcode:

1. File → Add Package Dependencies
2. Enter repository URL: `https://github.com/vizzly-testing/cli`
3. Select version and add to your UI test target
3. Select version and add the `VizzlyXCTest` product to your UI test target

The core `Vizzly` product has no XCTest dependency and can also be used from
native app or test-support code when you want to send PNG data directly.

Or add to your `Package.swift`:

```swift
dependencies: [
.package(url: "https://github.com/vizzly-testing/cli", from: "1.0.0")
],
targets: [
.testTarget(
name: "MyAppUITests",
dependencies: [
.product(name: "VizzlyXCTest", package: "cli")
]
)
]
```

### CocoaPods

```ruby
pod 'Vizzly', :git => 'https://github.com/vizzly-testing/cli', :branch => 'main'
```
Vizzly does not currently ship a CocoaPods podspec. Use Swift Package Manager
for native app integration.

## Quick Start

Expand All @@ -54,6 +62,7 @@ This starts a local server at `http://localhost:47392` that receives screenshots
```swift
import XCTest
import Vizzly
import VizzlyXCTest

class MyUITests: XCTestCase {
let app = XCUIApplication()
Expand Down Expand Up @@ -128,14 +137,17 @@ func testNavigationBar() {

```swift
func testAnimatedContent() {
// Allow up to 5% pixel difference (useful for animations)
// Allow a higher comparison threshold for animated content
app.vizzlyScreenshot(
name: "animated-banner",
threshold: 5
)
}
```

If `threshold` or `minClusterSize` is omitted, the server's configured
comparison settings are used.

### Multiple Device Orientations

```swift
Expand Down Expand Up @@ -187,7 +199,8 @@ extension XCUIApplication {
func vizzlyScreenshot(
name: String,
properties: [String: Any]? = nil,
threshold: Int = 0,
threshold: Double? = nil,
minClusterSize: Int? = nil,
fullPage: Bool = false
) -> [String: Any]?
}
Expand All @@ -200,7 +213,8 @@ extension XCUIElement {
func vizzlyScreenshot(
name: String,
properties: [String: Any]? = nil,
threshold: Int = 0
threshold: Double? = nil,
minClusterSize: Int? = nil
) -> [String: Any]?
}
```
Expand All @@ -213,15 +227,17 @@ extension XCTestCase {
name: String,
app: XCUIApplication,
properties: [String: Any]? = nil,
threshold: Int = 0,
threshold: Double? = nil,
minClusterSize: Int? = nil,
fullPage: Bool = false
) -> [String: Any]?

func vizzlyScreenshot(
name: String,
element: XCUIElement,
properties: [String: Any]? = nil,
threshold: Int = 0
threshold: Double? = nil,
minClusterSize: Int? = nil
) -> [String: Any]?
}
```
Expand All @@ -236,7 +252,8 @@ class VizzlyClient {
name: String,
image: Data,
properties: [String: Any]? = nil,
threshold: Int = 0,
threshold: Double? = nil,
minClusterSize: Int? = nil,
fullPage: Bool = false
) -> [String: Any]?

Expand All @@ -254,8 +271,9 @@ class VizzlyClient {
The SDK automatically discovers a running Vizzly TDD server using this priority order:

1. **VIZZLY_SERVER_URL environment variable** - Explicitly set server URL
2. **Global server file** - `~/.vizzly/server.json` written by CLI
3. **Default port health check** - Tests `http://localhost:47392/health`
2. **Project server file** - `.vizzly/server.json` in the current directory
3. **Global server file** - `~/.vizzly/server.json` written by CLI
4. **Default port health check** - Tests `http://localhost:47392/health`

When you run `vizzly tdd start`, the CLI automatically writes server info to `~/.vizzly/server.json` in your home directory, enabling zero-config discovery from iOS tests.

Expand Down Expand Up @@ -440,6 +458,18 @@ Check out the `Example/` directory for:
- Custom properties and thresholds
- Direct client usage

## SDK E2E Tests

The Swift SDK has an end-to-end test path that runs against a real local
Vizzly TDD server and uploads real PNG bytes through `VizzlyClient`:

```bash
npm run test:swift:e2e
```

This command builds the CLI, starts an isolated TDD run in a temp directory,
and executes the `VizzlyE2ETests` SwiftPM suite.

## Contributing

Bug reports and pull requests are welcome at https://github.com/vizzly-testing/cli
Expand Down
Loading
Loading