Skip to content

Commit 73e2d86

Browse files
committed
✅ Add Swift SDK E2E coverage
Run the Swift client against a real local Vizzly TDD server in an isolated temp workspace. Cover server discovery, PNG upload, new baseline creation, and repeated screenshot matching.
1 parent a5c09a0 commit 73e2d86

5 files changed

Lines changed: 158 additions & 0 deletions

File tree

clients/swift/Package.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,8 @@ let package = Package(
2727
.testTarget(
2828
name: "VizzlyTests",
2929
dependencies: ["Vizzly", "VizzlyXCTest"]),
30+
.testTarget(
31+
name: "VizzlyE2ETests",
32+
dependencies: ["Vizzly"]),
3033
]
3134
)

clients/swift/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,18 @@ Check out the `Example/` directory for:
458458
- Custom properties and thresholds
459459
- Direct client usage
460460

461+
## SDK E2E Tests
462+
463+
The Swift SDK has an end-to-end test path that runs against a real local
464+
Vizzly TDD server and uploads real PNG bytes through `VizzlyClient`:
465+
466+
```bash
467+
npm run test:swift:e2e
468+
```
469+
470+
This command builds the CLI, starts an isolated TDD run in a temp directory,
471+
and executes the `VizzlyE2ETests` SwiftPM suite.
472+
461473
## Contributing
462474

463475
Bug reports and pull requests are welcome at https://github.com/vizzly-testing/cli
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import XCTest
2+
import Vizzly
3+
4+
#if os(macOS)
5+
import AppKit
6+
#endif
7+
8+
final class VizzlyE2ETests: XCTestCase {
9+
override func setUpWithError() throws {
10+
try super.setUpWithError()
11+
12+
guard ProcessInfo.processInfo.environment["VIZZLY_E2E"] == "1" else {
13+
throw XCTSkip("Set VIZZLY_E2E=1 to run Swift SDK E2E tests")
14+
}
15+
}
16+
17+
func testUploadsScreenshotThroughRunningTddServer() throws {
18+
let client = VizzlyClient()
19+
XCTAssertTrue(client.isReady, "Expected VizzlyClient to discover the TDD server")
20+
21+
let firstResult = try XCTUnwrap(
22+
client.screenshot(
23+
name: "swift-sdk-e2e-home",
24+
image: try Self.makeTestPng(),
25+
properties: [
26+
"platform": "swift-e2e",
27+
"screen": "home"
28+
],
29+
threshold: 1.5,
30+
minClusterSize: 3,
31+
fullPage: true
32+
)
33+
)
34+
35+
XCTAssertTrue(
36+
Self.successStatuses.contains(Self.status(from: firstResult)),
37+
"Expected first upload to create or match a baseline, got: \(firstResult)"
38+
)
39+
XCTAssertEqual(firstResult["name"] as? String, "swift-sdk-e2e-home")
40+
XCTAssertNotNil(firstResult["current"])
41+
XCTAssertNotNil(firstResult["baseline"])
42+
}
43+
44+
func testSecondUploadMatchesExistingBaseline() throws {
45+
let client = VizzlyClient()
46+
47+
let firstResult = try XCTUnwrap(
48+
client.screenshot(
49+
name: "swift-sdk-e2e-repeatable",
50+
image: try Self.makeTestPng(),
51+
properties: ["case": "repeatable"]
52+
)
53+
)
54+
XCTAssertTrue(
55+
Self.successStatuses.contains(Self.status(from: firstResult)),
56+
"Expected first upload to create or match a baseline, got: \(firstResult)"
57+
)
58+
59+
let secondResult = try XCTUnwrap(
60+
client.screenshot(
61+
name: "swift-sdk-e2e-repeatable",
62+
image: try Self.makeTestPng(),
63+
properties: ["case": "repeatable"]
64+
)
65+
)
66+
XCTAssertEqual(Self.status(from: secondResult), "match")
67+
}
68+
69+
private static let successStatuses: Set<String> = ["new", "match"]
70+
71+
private static func status(from result: [String: Any]) -> String {
72+
return result["status"] as? String ?? ""
73+
}
74+
75+
private static func makeTestPng() throws -> Data {
76+
#if os(macOS)
77+
let image = NSImage(size: NSSize(width: 2, height: 2))
78+
image.lockFocus()
79+
NSColor.systemBlue.setFill()
80+
NSRect(x: 0, y: 0, width: 2, height: 2).fill()
81+
image.unlockFocus()
82+
83+
let tiffData = try XCTUnwrap(image.tiffRepresentation)
84+
let bitmap = try XCTUnwrap(NSBitmapImageRep(data: tiffData))
85+
return try XCTUnwrap(bitmap.representation(using: .png, properties: [:]))
86+
#else
87+
throw XCTSkip("Swift SDK E2E PNG fixture generation currently runs on macOS")
88+
#endif
89+
}
90+
}

clients/swift/scripts/run-e2e.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { spawn } from 'node:child_process';
2+
import { existsSync, mkdtempSync, rmSync } from 'node:fs';
3+
import { tmpdir } from 'node:os';
4+
import { dirname, join, resolve } from 'node:path';
5+
import { fileURLToPath } from 'node:url';
6+
7+
let scriptDir = dirname(fileURLToPath(import.meta.url));
8+
let swiftPackageDir = resolve(scriptDir, '..');
9+
let repoRoot = resolve(swiftPackageDir, '../..');
10+
let cliPath = join(repoRoot, 'bin/vizzly.js');
11+
let distCliPath = join(repoRoot, 'dist/cli.js');
12+
13+
if (!existsSync(distCliPath)) {
14+
console.error('Build the CLI first: npm run build');
15+
process.exit(1);
16+
}
17+
18+
let tempDir = mkdtempSync(join(tmpdir(), 'vizzly-swift-e2e-'));
19+
let swiftTestCommand = [
20+
'cd',
21+
JSON.stringify(swiftPackageDir),
22+
'&&',
23+
'swift',
24+
'test',
25+
'--filter',
26+
'VizzlyE2ETests',
27+
].join(' ');
28+
29+
let child = spawn(
30+
process.execPath,
31+
[cliPath, 'tdd', 'run', swiftTestCommand, '--no-color'],
32+
{
33+
cwd: tempDir,
34+
stdio: 'inherit',
35+
env: {
36+
...process.env,
37+
VIZZLY_E2E: '1',
38+
VIZZLY_HOME: join(tempDir, '.vizzly-home'),
39+
},
40+
}
41+
);
42+
43+
child.on('exit', code => {
44+
rmSync(tempDir, { recursive: true, force: true });
45+
process.exit(code ?? 1);
46+
});
47+
48+
child.on('error', error => {
49+
rmSync(tempDir, { recursive: true, force: true });
50+
console.error(error);
51+
process.exit(1);
52+
});

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"test:watch": "node --test --test-reporter=spec --watch $(find tests -name '*.test.js')",
7272
"test:reporter": "playwright test --config=tests/reporter/playwright.config.js",
7373
"test:reporter:visual": "node bin/vizzly.js run \"npm run test:reporter\"",
74+
"test:swift:e2e": "npm run build && node clients/swift/scripts/run-e2e.js",
7475
"test:tui": "node --test --test-reporter=spec tests/tui/*.test.js",
7576
"test:tui:docker": "./tests/tui/run-tui-tests.sh",
7677
"lint": "biome check src tests",

0 commit comments

Comments
 (0)