test(ios): XCUITest coverage for pairing/switcher/statusbar/settings/modbar/lock
Test target piRemoteUITests now covers 8 features across 7 files (~73s total).
UI tests:
- SmokeUITests: app launches
- PairingUITests: launchUnpaired→PairingFlow, deep-link auto-pair
- StatusBarUITests: three icon buttons (Switcher/Settings/Unpair)
- SessionSwitcherUITests: list, select, create-with-unique-name, cleanup
- SettingsUITests: open sheet, Face-ID toggle flip, content checks
- ModifierBarUITests: button presence, paste sheet
- LockScreenUITests: lock overlay via --force-lock
App-source changes for testability (all dev/uitest-only):
- AppState: --reset-state / --enable-faceid / --force-lock launch args
- piRemoteApp: --pair-with-url launch arg auto-triggers .onOpenURL
- MainTerminalView: --uitest mode replaces SwiftTerm with static
placeholder and skips WS connection to keep app idle for XCUI
- TerminalViewController.feed: defensive guard against nil terminalView
Accessibility identifiers added:
- StatusBar buttons: accessibilityLabel + identifier
- ModifierBar BarButton/RepeatingBarButton: accessibilityLabel + .isButton
- SessionSwitcher '+' button
Tooling notes:
- cliclick workaround replaced by simctl privacy grant pasteboard
- Tests pre-fetch fresh pair-token from /pair-qr each run
- SwiftUI Toggle inside Form needs coordinate tap (not .tap())
Bug fixes uncovered while writing tests:
- Sidecar POST /sessions response was missing 'state' field
(now returns { id, name, state, lastOutputAt } to match GET).
iOS SessionItem decoder hardened to default state='idle' when missing.
This commit is contained in:
parent
413c94601f
commit
d627fe8e67
|
|
@ -11,6 +11,19 @@ final class AppState: ObservableObject {
|
||||||
@Published var lastForegroundedAt: Date = Date()
|
@Published var lastForegroundedAt: Date = Date()
|
||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
|
// Test-only overrides
|
||||||
|
let args = ProcessInfo.processInfo.arguments
|
||||||
|
if args.contains("--reset-state") {
|
||||||
|
Keychain.shared.delete(key: "piremote.credential")
|
||||||
|
UserDefaults.standard.removeObject(forKey: "faceid.enabled")
|
||||||
|
}
|
||||||
|
if args.contains("--enable-faceid") {
|
||||||
|
UserDefaults.standard.set(true, forKey: "faceid.enabled")
|
||||||
|
}
|
||||||
|
if args.contains("--force-lock") {
|
||||||
|
isLocked = true
|
||||||
|
}
|
||||||
|
|
||||||
// Try loading persisted credential on launch
|
// Try loading persisted credential on launch
|
||||||
credential = try? Keychain.shared.load(key: "piremote.credential")
|
credential = try? Keychain.shared.load(key: "piremote.credential")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,15 @@ struct piRemoteApp: App {
|
||||||
.onAppear {
|
.onAppear {
|
||||||
notificationDelegate.setup()
|
notificationDelegate.setup()
|
||||||
UIApplication.shared.registerForRemoteNotifications()
|
UIApplication.shared.registerForRemoteNotifications()
|
||||||
|
|
||||||
|
// Test-only: auto-pair if argument present
|
||||||
|
if let pairArgIndex = ProcessInfo.processInfo.arguments.firstIndex(of: "--pair-with-url"),
|
||||||
|
pairArgIndex + 1 < ProcessInfo.processInfo.arguments.count {
|
||||||
|
let urlString = ProcessInfo.processInfo.arguments[pairArgIndex + 1]
|
||||||
|
if let url = URL(string: urlString) {
|
||||||
|
handlePairingURL(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.onOpenURL { url in
|
.onOpenURL { url in
|
||||||
handlePairingURL(url)
|
handlePairingURL(url)
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,16 @@ private struct SessionItem: Decodable {
|
||||||
let id: String
|
let id: String
|
||||||
let name: String
|
let name: String
|
||||||
let state: String
|
let state: String
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey { case id, name, state }
|
||||||
|
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let c = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
id = try c.decode(String.self, forKey: .id)
|
||||||
|
name = try c.decode(String.self, forKey: .name)
|
||||||
|
// Defensive: older sidecar versions omit `state` from POST /sessions.
|
||||||
|
state = (try? c.decode(String.self, forKey: .state)) ?? "idle"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Errors
|
// MARK: - Errors
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,8 @@ private struct BarButton: View {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain) // prevent SwiftUI from wrapping in extra chrome
|
.buttonStyle(.plain) // prevent SwiftUI from wrapping in extra chrome
|
||||||
|
.accessibilityLabel(title)
|
||||||
|
.accessibilityIdentifier("modbar.\(title)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,6 +240,11 @@ struct RepeatingBarButton: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
// Make it discoverable for XCUITest (Text + gesture isn't a button)
|
||||||
|
.accessibilityElement()
|
||||||
|
.accessibilityLabel(title)
|
||||||
|
.accessibilityIdentifier("modbar.\(title)")
|
||||||
|
.accessibilityAddTraits(.isButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Helpers
|
// MARK: Helpers
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ struct SessionSwitcher: View {
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "plus")
|
Image(systemName: "plus")
|
||||||
}
|
}
|
||||||
|
.accessibilityLabel("New Session")
|
||||||
|
.accessibilityIdentifier("sessionswitcher.new")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.alert("New Session", isPresented: $showNewSessionAlert) {
|
.alert("New Session", isPresented: $showNewSessionAlert) {
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ struct StatusBar: View {
|
||||||
Image(systemName: "list.bullet")
|
Image(systemName: "list.bullet")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
|
.accessibilityLabel("Switcher")
|
||||||
|
.accessibilityIdentifier("statusbar.switcher")
|
||||||
}
|
}
|
||||||
|
|
||||||
if onSettings != nil {
|
if onSettings != nil {
|
||||||
|
|
@ -48,6 +50,8 @@ struct StatusBar: View {
|
||||||
Image(systemName: "gear")
|
Image(systemName: "gear")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
|
.accessibilityLabel("Settings")
|
||||||
|
.accessibilityIdentifier("statusbar.settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
if onUnpair != nil {
|
if onUnpair != nil {
|
||||||
|
|
@ -58,6 +62,8 @@ struct StatusBar: View {
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(.red)
|
.foregroundStyle(.red)
|
||||||
}
|
}
|
||||||
|
.accessibilityLabel("Unpair")
|
||||||
|
.accessibilityIdentifier("statusbar.unpair")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,13 @@ struct MainTerminalView: View {
|
||||||
@StateObject private var registry = SessionRegistry() // T-2.6
|
@StateObject private var registry = SessionRegistry() // T-2.6
|
||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
|
|
||||||
|
/// True when running under XCUITest. Skips the live SwiftTerm view + WS
|
||||||
|
/// connection, which otherwise keep the app non-idle and cause every
|
||||||
|
/// XCUITest interaction to block for ~120 s.
|
||||||
|
private var isUITest: Bool {
|
||||||
|
ProcessInfo.processInfo.arguments.contains("--uitest")
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
// ── Status bar ──────────────────────────────────────────
|
// ── Status bar ──────────────────────────────────────────
|
||||||
|
|
@ -34,8 +41,14 @@ struct MainTerminalView: View {
|
||||||
)
|
)
|
||||||
|
|
||||||
// ── Terminal ────────────────────────────────────────────
|
// ── Terminal ────────────────────────────────────────────
|
||||||
|
if isUITest {
|
||||||
|
Color.black
|
||||||
|
.overlay(Text("UITest mode").foregroundStyle(.white).font(.caption))
|
||||||
|
.accessibilityIdentifier("terminal.placeholder")
|
||||||
|
} else {
|
||||||
TerminalViewRepresentable(controller: terminalVC)
|
TerminalViewRepresentable(controller: terminalVC)
|
||||||
.ignoresSafeArea(edges: .bottom)
|
.ignoresSafeArea(edges: .bottom)
|
||||||
|
}
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|
||||||
|
|
@ -52,6 +65,8 @@ struct MainTerminalView: View {
|
||||||
.task { await registry.refresh(credential: credential) } // T-2.6
|
.task { await registry.refresh(credential: credential) } // T-2.6
|
||||||
.onChange(of: activeSessionId) { _, newId in
|
.onChange(of: activeSessionId) { _, newId in
|
||||||
guard let newId else { return }
|
guard let newId else { return }
|
||||||
|
// UI-test mode: no terminal view, no WS — just update the label.
|
||||||
|
if isUITest { sessionName = newId; return }
|
||||||
// Avoid reconnect storm if id already matches the current connection.
|
// Avoid reconnect storm if id already matches the current connection.
|
||||||
if connection?.id == newId { return }
|
if connection?.id == newId { return }
|
||||||
Task {
|
Task {
|
||||||
|
|
@ -78,6 +93,15 @@ struct MainTerminalView: View {
|
||||||
// MARK: - Bootstrap
|
// MARK: - Bootstrap
|
||||||
|
|
||||||
private func initialBootstrap() async {
|
private func initialBootstrap() async {
|
||||||
|
// UI-test mode: skip the live WebSocket. SwiftTerm's constant redraw
|
||||||
|
// on incoming frames prevents XCUITest's idle wait from completing,
|
||||||
|
// making every .tap() block for ~120 s. Status bar, modifier bar, and
|
||||||
|
// both sheets still render normally.
|
||||||
|
if ProcessInfo.processInfo.arguments.contains("--uitest") {
|
||||||
|
statusText = "● uitest"
|
||||||
|
sessionName = "uitest"
|
||||||
|
return
|
||||||
|
}
|
||||||
statusText = "Looking for sessions…"
|
statusText = "Looking for sessions…"
|
||||||
do {
|
do {
|
||||||
let sessionId = try await resolveSession()
|
let sessionId = try await resolveSession()
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,9 @@ public final class TerminalViewController: UIViewController {
|
||||||
/// SwiftTerm's `feed(byteArray:)` is thread-safe; this wrapper is
|
/// SwiftTerm's `feed(byteArray:)` is thread-safe; this wrapper is
|
||||||
/// intentionally @MainActor so callers remain on the main actor.
|
/// intentionally @MainActor so callers remain on the main actor.
|
||||||
public func feed(data: Data) {
|
public func feed(data: Data) {
|
||||||
|
guard let tv = terminalView else { return }
|
||||||
let bytes = [UInt8](data)
|
let bytes = [UInt8](data)
|
||||||
terminalView.feed(byteArray: bytes[...])
|
tv.feed(byteArray: bytes[...])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Feed a base64-encoded ANSI snapshot (e.g. from the sidecar's
|
/// Feed a base64-encoded ANSI snapshot (e.g. from the sidecar's
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
import Foundation
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
extension XCUIApplication {
|
||||||
|
|
||||||
|
/// Launch with a freshly-fetched pairing URL so the test starts from a
|
||||||
|
/// known paired state. Hits `/pair-qr` on the sidecar to obtain a
|
||||||
|
/// one-time-use token, then passes it to the app via launch args.
|
||||||
|
/// Fails the current test if the sidecar is unreachable.
|
||||||
|
func launchPaired(file: StaticString = #file, line: UInt = #line) {
|
||||||
|
guard let url = TestSidecar.freshPairURL() else {
|
||||||
|
XCTFail("Could not fetch fresh pair URL from sidecar — is it running?",
|
||||||
|
file: file, line: line)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
launchArguments = ["--uitest", "--reset-state", "--pair-with-url", url]
|
||||||
|
launch()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Launch with state reset so the PairingFlowView is shown.
|
||||||
|
func launchUnpaired() {
|
||||||
|
launchArguments = ["--uitest", "--reset-state"]
|
||||||
|
launch()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Launch with a specific pairing URL (for the explicit deep-link test).
|
||||||
|
func launchWithPairing(url: String) {
|
||||||
|
launchArguments = ["--uitest", "--reset-state", "--pair-with-url", url]
|
||||||
|
launch()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Launch directly into the lock screen (faceid enabled + forced lock).
|
||||||
|
/// Resets state first so the test isn't polluted by previous runs.
|
||||||
|
func launchLocked() {
|
||||||
|
launchArguments = ["--uitest", "--reset-state", "--enable-faceid", "--force-lock"]
|
||||||
|
launch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Sidecar helpers
|
||||||
|
|
||||||
|
enum TestSidecar {
|
||||||
|
static let baseURL = "http://10.13.37.2:17373"
|
||||||
|
static let bearer = "GeoZytsPPGwItCHRNu8EwoZGlHH5iUAx"
|
||||||
|
|
||||||
|
/// Synchronously fetch a fresh pairing URL from the sidecar.
|
||||||
|
static func freshPairURL() -> String? {
|
||||||
|
let url = URL(string: "\(baseURL)/pair-qr?token=\(bearer)&format=url")!
|
||||||
|
var result: String?
|
||||||
|
let sem = DispatchSemaphore(value: 0)
|
||||||
|
URLSession.shared.dataTask(with: url) { data, _, _ in
|
||||||
|
defer { sem.signal() }
|
||||||
|
guard let data = data,
|
||||||
|
let text = String(data: data, encoding: .utf8) else { return }
|
||||||
|
if let match = text.range(of: #"pi-remote://[^\s]+"#,
|
||||||
|
options: .regularExpression) {
|
||||||
|
result = String(text[match])
|
||||||
|
}
|
||||||
|
}.resume()
|
||||||
|
_ = sem.wait(timeout: .now() + 5)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete a session via the sidecar REST API (best-effort, for cleanup).
|
||||||
|
static func deleteSession(_ id: String) {
|
||||||
|
var req = URLRequest(url: URL(string: "\(baseURL)/sessions/\(id)")!)
|
||||||
|
req.httpMethod = "DELETE"
|
||||||
|
req.setValue("Bearer \(bearer)", forHTTPHeaderField: "Authorization")
|
||||||
|
let sem = DispatchSemaphore(value: 0)
|
||||||
|
URLSession.shared.dataTask(with: req) { _, _, _ in sem.signal() }.resume()
|
||||||
|
_ = sem.wait(timeout: .now() + 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
final class LockScreenUITests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLockScreenAppearance() throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launchLocked()
|
||||||
|
|
||||||
|
// Assert LockView is showing
|
||||||
|
let lockText = app.staticTexts["Locked"]
|
||||||
|
XCTAssertTrue(lockText.waitForExistence(timeout: 5), "Lock screen should be visible when forced")
|
||||||
|
|
||||||
|
// We can't easily test Face ID success in simulator without manual menu interaction,
|
||||||
|
// so we just verify the lock screen is presented.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
final class ModifierBarUITests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func testModifierBarButtons() throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launchPaired()
|
||||||
|
|
||||||
|
// List of buttons to verify
|
||||||
|
// Wait until the terminal view is up and the modifier bar visible.
|
||||||
|
XCTAssertTrue(app.buttons["Ctrl"].waitForExistence(timeout: 10),
|
||||||
|
"Modifier bar should appear after pairing")
|
||||||
|
|
||||||
|
let buttons = [
|
||||||
|
"Ctrl", "Esc", "Tab", "←", "↑", "↓", "→", "⇧↵", "📋"
|
||||||
|
]
|
||||||
|
|
||||||
|
for title in buttons {
|
||||||
|
let btn = app.buttons[title]
|
||||||
|
XCTAssertTrue(btn.exists, "Modifier button '\(title)' should be present")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Ctrl sticky state
|
||||||
|
let ctrlBtn = app.buttons["Ctrl"]
|
||||||
|
// In SwiftUI, the visual state (background color) isn't directly accessible via XCUITest
|
||||||
|
// unless we add accessibilityValue or similar.
|
||||||
|
// However, we can verify that tapping it doesn't crash and the app remains responsive.
|
||||||
|
ctrlBtn.tap()
|
||||||
|
|
||||||
|
// Tap a few other buttons
|
||||||
|
app.buttons["Esc"].tap()
|
||||||
|
app.buttons["↑"].tap()
|
||||||
|
app.buttons["📋"].tap()
|
||||||
|
|
||||||
|
// Verify PasteSheet appears (navigationTitle is "Paste")
|
||||||
|
let pasteSheetTitle = app.staticTexts["Paste"]
|
||||||
|
XCTAssertTrue(pasteSheetTitle.waitForExistence(timeout: 5), "Paste sheet should appear after tapping clipboard button")
|
||||||
|
|
||||||
|
// Dismiss PasteSheet
|
||||||
|
app.buttons["Cancel"].tap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
final class PairingUITests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLaunchUnpairedShowsPairingFlow() throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launchUnpaired()
|
||||||
|
|
||||||
|
// Assert PairingFlowView is showing
|
||||||
|
let scanButton = app.buttons["Tap to Scan"]
|
||||||
|
XCTAssertTrue(scanButton.waitForExistence(timeout: 5), "PairingFlowView should be visible on unpaired launch")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAutoPairingViaLaunchArgument() throws {
|
||||||
|
guard let pairingURL = TestSidecar.freshPairURL() else {
|
||||||
|
throw XCTSkip("Could not fetch fresh pair URL - sidecar may be down")
|
||||||
|
}
|
||||||
|
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launchWithPairing(url: pairingURL)
|
||||||
|
|
||||||
|
let switcherButton = app.buttons["Switcher"]
|
||||||
|
XCTAssertTrue(switcherButton.waitForExistence(timeout: 15),
|
||||||
|
"App should auto-pair and show MainTerminalView")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
final class SessionSwitcherUITests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSessionSwitcherFlow() throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launchPaired()
|
||||||
|
|
||||||
|
// 1. Open Switcher
|
||||||
|
let switcherButton = app.buttons["Switcher"]
|
||||||
|
XCTAssertTrue(switcherButton.waitForExistence(timeout: 10))
|
||||||
|
switcherButton.tap()
|
||||||
|
|
||||||
|
// 2. Assert Navigation Title
|
||||||
|
let navTitle = app.staticTexts["Sessions"]
|
||||||
|
XCTAssertTrue(navTitle.waitForExistence(timeout: 5), "Session switcher sheet should have title 'Sessions'")
|
||||||
|
|
||||||
|
// 3. Assert existing sessions
|
||||||
|
let mainSession = app.staticTexts["main"]
|
||||||
|
let workSession = app.staticTexts["work"]
|
||||||
|
let logsSession = app.staticTexts["logs"]
|
||||||
|
|
||||||
|
XCTAssertTrue(mainSession.exists, "Session 'main' should be present")
|
||||||
|
XCTAssertTrue(workSession.exists, "Session 'work' should be present")
|
||||||
|
XCTAssertTrue(logsSession.exists, "Session 'logs' should be present")
|
||||||
|
|
||||||
|
// 4. Select 'main' and verify dismissal
|
||||||
|
mainSession.tap()
|
||||||
|
XCTAssertFalse(navTitle.waitForExistence(timeout: 5), "Sheet should dismiss after selecting a session")
|
||||||
|
|
||||||
|
// 5. Create new session
|
||||||
|
switcherButton.tap()
|
||||||
|
let addButton = app.buttons["New Session"]
|
||||||
|
XCTAssertTrue(addButton.waitForExistence(timeout: 5))
|
||||||
|
addButton.tap()
|
||||||
|
|
||||||
|
let nameField = app.textFields["Session name"]
|
||||||
|
XCTAssertTrue(nameField.waitForExistence(timeout: 5))
|
||||||
|
nameField.tap()
|
||||||
|
let uniqueName = "uitest-\(Int(Date().timeIntervalSince1970))"
|
||||||
|
nameField.typeText(uniqueName)
|
||||||
|
|
||||||
|
let createButton = app.buttons["Create"]
|
||||||
|
XCTAssertTrue(createButton.exists)
|
||||||
|
createButton.tap()
|
||||||
|
|
||||||
|
// 6. Verify new session appears (refresh runs async after spawn;
|
||||||
|
// allow extra time for the sidecar round-trip + list rerender).
|
||||||
|
let newSession = app.staticTexts[uniqueName]
|
||||||
|
if !newSession.waitForExistence(timeout: 15) {
|
||||||
|
// Capture diagnostic info to file before failing
|
||||||
|
let screenshot = XCUIScreen.main.screenshot()
|
||||||
|
let att = XCTAttachment(screenshot: screenshot)
|
||||||
|
att.lifetime = .keepAlways
|
||||||
|
att.name = "session-switcher-failure"
|
||||||
|
add(att)
|
||||||
|
let hierarchy = XCTAttachment(string: app.debugDescription)
|
||||||
|
hierarchy.lifetime = .keepAlways
|
||||||
|
hierarchy.name = "hierarchy"
|
||||||
|
add(hierarchy)
|
||||||
|
XCTFail("New session '\(uniqueName)' should appear in the list")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup: delete via sidecar API
|
||||||
|
TestSidecar.deleteSession(uniqueName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
final class SettingsUITests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSettingsView() throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launchPaired()
|
||||||
|
|
||||||
|
// 1. Open Settings
|
||||||
|
let settingsButton = app.buttons["Settings"]
|
||||||
|
XCTAssertTrue(settingsButton.waitForExistence(timeout: 10))
|
||||||
|
settingsButton.tap()
|
||||||
|
|
||||||
|
// 2. Assert Navigation Title
|
||||||
|
let navTitle = app.staticTexts["Settings"]
|
||||||
|
XCTAssertTrue(navTitle.waitForExistence(timeout: 5), "Settings sheet should have title 'Settings'")
|
||||||
|
|
||||||
|
// 3. Assert section content (SwiftUI renders Section headers as
|
||||||
|
// uppercase "SECURITY" etc. but visibility is fragile across SDKs.
|
||||||
|
// Asserting on the section's contents is more robust.)
|
||||||
|
XCTAssertTrue(app.switches["Require Face ID"].waitForExistence(timeout: 5),
|
||||||
|
"Security → Face ID toggle should exist")
|
||||||
|
XCTAssertTrue(app.buttons["Unpair"].exists,
|
||||||
|
"Danger → Unpair button should exist")
|
||||||
|
|
||||||
|
// 4. Toggle Face ID. SwiftUI's Toggle inside a Form is famously
|
||||||
|
// sticky for XCUI's .tap() — a coordinate hit on the switch itself
|
||||||
|
// is more reliable.
|
||||||
|
let faceIDToggle = app.switches["Require Face ID"]
|
||||||
|
XCTAssertTrue(faceIDToggle.exists, "Require Face ID toggle should exist")
|
||||||
|
let initialState = faceIDToggle.value as? String
|
||||||
|
faceIDToggle.coordinate(withNormalizedOffset: CGVector(dx: 0.95, dy: 0.5)).tap()
|
||||||
|
// Give SwiftUI a moment to update + persist into UserDefaults.
|
||||||
|
let flipped = NSPredicate(format: "value != %@", initialState ?? "")
|
||||||
|
expectation(for: flipped, evaluatedWith: faceIDToggle, handler: nil)
|
||||||
|
waitForExpectations(timeout: 3)
|
||||||
|
|
||||||
|
// 5. Verify Sidecar Info
|
||||||
|
// Host:Port is in a LabeledContent. In XCUITest, LabeledContent often appears as two staticTexts.
|
||||||
|
// We look for the value that matches the pattern.
|
||||||
|
let hostText = app.staticTexts.matching(NSPredicate(format: "label CONTAINS '10.13.37.2:17373'")).firstMatch
|
||||||
|
XCTAssertTrue(hostText.exists, "Sidecar host:port should be displayed correctly")
|
||||||
|
|
||||||
|
// 6. Dismiss
|
||||||
|
let doneButton = app.buttons["Done"]
|
||||||
|
XCTAssertTrue(doneButton.exists)
|
||||||
|
doneButton.tap()
|
||||||
|
XCTAssertFalse(navTitle.waitForExistence(timeout: 5), "Settings sheet should dismiss")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
final class StatusBarUITests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
continueAfterFailure = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func testStatusBarButtonsPresence() throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launchPaired()
|
||||||
|
|
||||||
|
let switcherButton = app.buttons["Switcher"]
|
||||||
|
let settingsButton = app.buttons["Settings"]
|
||||||
|
let unpairButton = app.buttons["Unpair"]
|
||||||
|
|
||||||
|
XCTAssertTrue(switcherButton.waitForExistence(timeout: 10), "Switcher button should be present")
|
||||||
|
XCTAssertTrue(settingsButton.waitForExistence(timeout: 5), "Settings button should be present")
|
||||||
|
XCTAssertTrue(unpairButton.waitForExistence(timeout: 5), "Unpair button should be present")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,9 +7,12 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
0572AF0EFE02ABD12CD5C584 /* SmokeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE5E1A0BE69AF1FEF73E373F /* SmokeUITests.swift */; };
|
||||||
05CD861F694B84577A4B5A27 /* PairingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9BAF4FBE6CC23FDD9B40040 /* PairingTests.swift */; };
|
05CD861F694B84577A4B5A27 /* PairingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9BAF4FBE6CC23FDD9B40040 /* PairingTests.swift */; };
|
||||||
09AC16350B4E83B71B05A9D5 /* ResumeCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7961BE126AFEEE4B7AA6621 /* ResumeCursor.swift */; };
|
09AC16350B4E83B71B05A9D5 /* ResumeCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7961BE126AFEEE4B7AA6621 /* ResumeCursor.swift */; };
|
||||||
|
132F60783EC43AE420FA7CD5 /* LockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94525E2A804BF64F12806D4E /* LockView.swift */; };
|
||||||
16095F16FAB72320676A729D /* ResumeCursorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7607FF3804A2602B1C6A05D4 /* ResumeCursorTests.swift */; };
|
16095F16FAB72320676A729D /* ResumeCursorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7607FF3804A2602B1C6A05D4 /* ResumeCursorTests.swift */; };
|
||||||
|
17F996CE1F5CF3FF12E5C1AB /* LockScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF52ADD110456E368EAE217C /* LockScreenUITests.swift */; };
|
||||||
19E584DD72E8F6DE3AF4E77F /* MainTerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D4E4BB86FBFBD80287048C1 /* MainTerminalView.swift */; };
|
19E584DD72E8F6DE3AF4E77F /* MainTerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D4E4BB86FBFBD80287048C1 /* MainTerminalView.swift */; };
|
||||||
1F353AB548615ECD7D241EF7 /* SessionConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F95D26CD899B18D07AB0B2 /* SessionConnection.swift */; };
|
1F353AB548615ECD7D241EF7 /* SessionConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F95D26CD899B18D07AB0B2 /* SessionConnection.swift */; };
|
||||||
2AA3AC859917D32C1444FC5B /* FrameCodec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B6B497329B98A4508D963B /* FrameCodec.swift */; };
|
2AA3AC859917D32C1444FC5B /* FrameCodec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B6B497329B98A4508D963B /* FrameCodec.swift */; };
|
||||||
|
|
@ -18,10 +21,12 @@
|
||||||
30E07FF586EABBBB8C70AE60 /* piRemoteApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D747BC787A24B4E225B142 /* piRemoteApp.swift */; };
|
30E07FF586EABBBB8C70AE60 /* piRemoteApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D747BC787A24B4E225B142 /* piRemoteApp.swift */; };
|
||||||
3486C15393498F5306C8F43B /* ScrollbackCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22658EED98A0B3C2183AACDD /* ScrollbackCacheTests.swift */; };
|
3486C15393498F5306C8F43B /* ScrollbackCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22658EED98A0B3C2183AACDD /* ScrollbackCacheTests.swift */; };
|
||||||
3AC56484E8AC068C10F31324 /* REVIEW_NOTES.md in Resources */ = {isa = PBXBuildFile; fileRef = 6DE4A325EEA53870390B89D9 /* REVIEW_NOTES.md */; };
|
3AC56484E8AC068C10F31324 /* REVIEW_NOTES.md in Resources */ = {isa = PBXBuildFile; fileRef = 6DE4A325EEA53870390B89D9 /* REVIEW_NOTES.md */; };
|
||||||
|
4334301CFE20E6B66BDE7D19 /* SessionSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8C77FC9D24BB5F8DA96386C /* SessionSwitcher.swift */; };
|
||||||
4877B4085C529C640FBBE6AB /* ThemeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC48E39D19238178A180B30C /* ThemeStore.swift */; };
|
4877B4085C529C640FBBE6AB /* ThemeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC48E39D19238178A180B30C /* ThemeStore.swift */; };
|
||||||
56096DB64F700FC00C4D58CE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFF032BC30D513204211ADA5 /* Assets.xcassets */; };
|
56096DB64F700FC00C4D58CE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFF032BC30D513204211ADA5 /* Assets.xcassets */; };
|
||||||
5F82D50C477F47893FADA8CB /* PasteSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F776605A4109C047E44A89 /* PasteSheet.swift */; };
|
5F82D50C477F47893FADA8CB /* PasteSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F776605A4109C047E44A89 /* PasteSheet.swift */; };
|
||||||
5F8F5E6D2D5277CB90FA98A0 /* ThemeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99FA0A0FD737901834AD5705 /* ThemeTests.swift */; };
|
5F8F5E6D2D5277CB90FA98A0 /* ThemeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99FA0A0FD737901834AD5705 /* ThemeTests.swift */; };
|
||||||
|
6A52DBC5C2845ADA05B37A35 /* SessionRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 959878B4816DD2617038A339 /* SessionRegistry.swift */; };
|
||||||
734F2FECD358816F695D26CD /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62DD6C03615573E339057EBF /* AppState.swift */; };
|
734F2FECD358816F695D26CD /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62DD6C03615573E339057EBF /* AppState.swift */; };
|
||||||
7936EDE3DC79D02CF66F8863 /* QRScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AF0B5FBC3ACEC8EF5C3FF12 /* QRScannerView.swift */; };
|
7936EDE3DC79D02CF66F8863 /* QRScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AF0B5FBC3ACEC8EF5C3FF12 /* QRScannerView.swift */; };
|
||||||
7BD37B4A99532FD542D21526 /* TerminalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75BE928FA90D8AF2C56615D /* TerminalViewController.swift */; };
|
7BD37B4A99532FD542D21526 /* TerminalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75BE928FA90D8AF2C56615D /* TerminalViewController.swift */; };
|
||||||
|
|
@ -29,9 +34,14 @@
|
||||||
909A26B85FA298A870E407CD /* DeviceTokenRegistrar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03ABB7E636E55917562D9A2C /* DeviceTokenRegistrar.swift */; };
|
909A26B85FA298A870E407CD /* DeviceTokenRegistrar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03ABB7E636E55917562D9A2C /* DeviceTokenRegistrar.swift */; };
|
||||||
9855E1E1C856E20B339F2A0A /* NotificationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844A9C78194E7644A78FFA23 /* NotificationDelegate.swift */; };
|
9855E1E1C856E20B339F2A0A /* NotificationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844A9C78194E7644A78FFA23 /* NotificationDelegate.swift */; };
|
||||||
9AC28FD7FD38F250FE477441 /* ScrollbackCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98EF1F714A1A5E8D4C3DA2B /* ScrollbackCache.swift */; };
|
9AC28FD7FD38F250FE477441 /* ScrollbackCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98EF1F714A1A5E8D4C3DA2B /* ScrollbackCache.swift */; };
|
||||||
|
9BDEBAD2C295FDD53946FB8C /* ModifierBarUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E689590D75F152E90467016 /* ModifierBarUITests.swift */; };
|
||||||
|
9E4B31AA31D8A900D36918A3 /* FaceIDGate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87407DA9C464BA9C9E118308 /* FaceIDGate.swift */; };
|
||||||
|
A1527F94754A9205576C317C /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1F7B03B47D7766D72BA3B8 /* Helpers.swift */; };
|
||||||
A1B807C3E8586E99507463B9 /* FrameCodecTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85D5F5AF59E84DDC3AE168B /* FrameCodecTests.swift */; };
|
A1B807C3E8586E99507463B9 /* FrameCodecTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85D5F5AF59E84DDC3AE168B /* FrameCodecTests.swift */; };
|
||||||
A3144EA79E01CB9D2DD552C8 /* PairingFlowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38B86E930CB34DEB9E4C144 /* PairingFlowView.swift */; };
|
A3144EA79E01CB9D2DD552C8 /* PairingFlowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38B86E930CB34DEB9E4C144 /* PairingFlowView.swift */; };
|
||||||
|
A51AABE190B66EE994D8415B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BCDE8061BF3E2DABEA12E7 /* SettingsView.swift */; };
|
||||||
A56F82D6CEC7C6654C02C7BB /* WebSocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5205F823929F91450C58D4CA /* WebSocketClient.swift */; };
|
A56F82D6CEC7C6654C02C7BB /* WebSocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5205F823929F91450C58D4CA /* WebSocketClient.swift */; };
|
||||||
|
AEAB8079223530B0437F3434 /* PairingUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEC5B3171A29F91F7D9B67E /* PairingUITests.swift */; };
|
||||||
AF1F7740D9A9F40BA8308052 /* TerminalViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39536FD31585716EF30C84C6 /* TerminalViewRepresentable.swift */; };
|
AF1F7740D9A9F40BA8308052 /* TerminalViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39536FD31585716EF30C84C6 /* TerminalViewRepresentable.swift */; };
|
||||||
B3809456CF2E96F1B1B862C2 /* FontStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12767F24EC6ECFA77B280A8D /* FontStore.swift */; };
|
B3809456CF2E96F1B1B862C2 /* FontStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12767F24EC6ECFA77B280A8D /* FontStore.swift */; };
|
||||||
B73AD1B4B8830C1DEE8A78AE /* ModifierStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 278215F3FD64C681C55F23A4 /* ModifierStateTests.swift */; };
|
B73AD1B4B8830C1DEE8A78AE /* ModifierStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 278215F3FD64C681C55F23A4 /* ModifierStateTests.swift */; };
|
||||||
|
|
@ -39,16 +49,28 @@
|
||||||
C1F266B0DC9D7029E5E5B203 /* DeviceTokenRegistrarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83446A0D895B866E880D4F2D /* DeviceTokenRegistrarTests.swift */; };
|
C1F266B0DC9D7029E5E5B203 /* DeviceTokenRegistrarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83446A0D895B866E880D4F2D /* DeviceTokenRegistrarTests.swift */; };
|
||||||
C776D609DB29E5B4C90881F9 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = B772854E3FADA8998C93DAF5 /* Keychain.swift */; };
|
C776D609DB29E5B4C90881F9 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = B772854E3FADA8998C93DAF5 /* Keychain.swift */; };
|
||||||
C823749124F98D46FB993247 /* KeychainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F47CA5A1045A264958B360BF /* KeychainTests.swift */; };
|
C823749124F98D46FB993247 /* KeychainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F47CA5A1045A264958B360BF /* KeychainTests.swift */; };
|
||||||
|
C87E6CCFC4ADC4AC4CAC4C0D /* SessionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3C69D7879985E77A45DE76 /* SessionRow.swift */; };
|
||||||
D3E1C0562B97260D28FF1C11 /* Pairing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F544C25D53F52291E2FDB6F /* Pairing.swift */; };
|
D3E1C0562B97260D28FF1C11 /* Pairing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F544C25D53F52291E2FDB6F /* Pairing.swift */; };
|
||||||
D3E8D6064F38E4024A6863C9 /* TerminalTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3A7FB4B9C4D2B63B016E11A /* TerminalTheme.swift */; };
|
D3E8D6064F38E4024A6863C9 /* TerminalTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3A7FB4B9C4D2B63B016E11A /* TerminalTheme.swift */; };
|
||||||
D77D662C3311D9646BE57596 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */; };
|
D77D662C3311D9646BE57596 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */; };
|
||||||
|
D8F05ED47CD1A4A8298EDDFB /* StatusBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C66962D8B5B6869B60F8101 /* StatusBar.swift */; };
|
||||||
E9126D5D059DAD3717FA2398 /* ModifierBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F553E905D716538D9DA442E7 /* ModifierBar.swift */; };
|
E9126D5D059DAD3717FA2398 /* ModifierBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F553E905D716538D9DA442E7 /* ModifierBar.swift */; };
|
||||||
|
EAF7C85B3223C503829028D3 /* SettingsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A48B8A34A0647A8BF12B55 /* SettingsUITests.swift */; };
|
||||||
|
EF47351AD35418E508ED33C9 /* SessionSwitcherUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED280CEF6D334529433F20A3 /* SessionSwitcherUITests.swift */; };
|
||||||
|
F10312EF88278BB719CCF7E7 /* StatusBarUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D30D90D7888D84A2EF1B22EA /* StatusBarUITests.swift */; };
|
||||||
F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 188683139B863ED1AC03A1BB /* ContentView.swift */; };
|
F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 188683139B863ED1AC03A1BB /* ContentView.swift */; };
|
||||||
F8CBA52AE2CC3D8496361D45 /* TerminalFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5B05BBDD469F51657ED89B0 /* TerminalFont.swift */; };
|
F8CBA52AE2CC3D8496361D45 /* TerminalFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5B05BBDD469F51657ED89B0 /* TerminalFont.swift */; };
|
||||||
FADABBF0D0229D84832D3B78 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = D095700C52C60FDA2CB38679 /* SwiftTerm */; };
|
FADABBF0D0229D84832D3B78 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = D095700C52C60FDA2CB38679 /* SwiftTerm */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
4BC4CAFF5DFB43FCB5A72089 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = B5A2356AA5371FBA25136FA6 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 4910ACCEB67B73CBA3440774;
|
||||||
|
remoteInfo = piRemote;
|
||||||
|
};
|
||||||
B301DDFED8092F66145718E3 /* PBXContainerItemProxy */ = {
|
B301DDFED8092F66145718E3 /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = B5A2356AA5371FBA25136FA6 /* Project object */;
|
containerPortal = B5A2356AA5371FBA25136FA6 /* Project object */;
|
||||||
|
|
@ -61,18 +83,22 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
03ABB7E636E55917562D9A2C /* DeviceTokenRegistrar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTokenRegistrar.swift; sourceTree = "<group>"; };
|
03ABB7E636E55917562D9A2C /* DeviceTokenRegistrar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTokenRegistrar.swift; sourceTree = "<group>"; };
|
||||||
0AF0B5FBC3ACEC8EF5C3FF12 /* QRScannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerView.swift; sourceTree = "<group>"; };
|
0AF0B5FBC3ACEC8EF5C3FF12 /* QRScannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerView.swift; sourceTree = "<group>"; };
|
||||||
|
0C66962D8B5B6869B60F8101 /* StatusBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBar.swift; sourceTree = "<group>"; };
|
||||||
0E401DECD467A1D3AB030610 /* piRemote.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = piRemote.entitlements; sourceTree = "<group>"; };
|
0E401DECD467A1D3AB030610 /* piRemote.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = piRemote.entitlements; sourceTree = "<group>"; };
|
||||||
0F544C25D53F52291E2FDB6F /* Pairing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pairing.swift; sourceTree = "<group>"; };
|
0F544C25D53F52291E2FDB6F /* Pairing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pairing.swift; sourceTree = "<group>"; };
|
||||||
12767F24EC6ECFA77B280A8D /* FontStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontStore.swift; sourceTree = "<group>"; };
|
12767F24EC6ECFA77B280A8D /* FontStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontStore.swift; sourceTree = "<group>"; };
|
||||||
15B6B497329B98A4508D963B /* FrameCodec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameCodec.swift; sourceTree = "<group>"; };
|
15B6B497329B98A4508D963B /* FrameCodec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameCodec.swift; sourceTree = "<group>"; };
|
||||||
188683139B863ED1AC03A1BB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
188683139B863ED1AC03A1BB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
|
1E689590D75F152E90467016 /* ModifierBarUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierBarUITests.swift; sourceTree = "<group>"; };
|
||||||
22658EED98A0B3C2183AACDD /* ScrollbackCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollbackCacheTests.swift; sourceTree = "<group>"; };
|
22658EED98A0B3C2183AACDD /* ScrollbackCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollbackCacheTests.swift; sourceTree = "<group>"; };
|
||||||
278215F3FD64C681C55F23A4 /* ModifierStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierStateTests.swift; sourceTree = "<group>"; };
|
278215F3FD64C681C55F23A4 /* ModifierStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierStateTests.swift; sourceTree = "<group>"; };
|
||||||
|
2C3C69D7879985E77A45DE76 /* SessionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRow.swift; sourceTree = "<group>"; };
|
||||||
2E2370A3190FDC144C822FF6 /* piRemote.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = piRemote.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
2E2370A3190FDC144C822FF6 /* piRemote.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = piRemote.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
39536FD31585716EF30C84C6 /* TerminalViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalViewRepresentable.swift; sourceTree = "<group>"; };
|
39536FD31585716EF30C84C6 /* TerminalViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalViewRepresentable.swift; sourceTree = "<group>"; };
|
||||||
3D4E4BB86FBFBD80287048C1 /* MainTerminalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTerminalView.swift; sourceTree = "<group>"; };
|
3D4E4BB86FBFBD80287048C1 /* MainTerminalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTerminalView.swift; sourceTree = "<group>"; };
|
||||||
5205F823929F91450C58D4CA /* WebSocketClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocketClient.swift; sourceTree = "<group>"; };
|
5205F823929F91450C58D4CA /* WebSocketClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocketClient.swift; sourceTree = "<group>"; };
|
||||||
55DAE4BC86AE950146CD7B94 /* REVIEW_NOTES_2.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = REVIEW_NOTES_2.md; sourceTree = "<group>"; };
|
55DAE4BC86AE950146CD7B94 /* REVIEW_NOTES_2.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = REVIEW_NOTES_2.md; sourceTree = "<group>"; };
|
||||||
|
5C1F7B03B47D7766D72BA3B8 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
|
||||||
62DD6C03615573E339057EBF /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
|
62DD6C03615573E339057EBF /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
|
||||||
658CB2FCA96A8913B1753B1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
658CB2FCA96A8913B1753B1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||||
67F95D26CD899B18D07AB0B2 /* SessionConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionConnection.swift; sourceTree = "<group>"; };
|
67F95D26CD899B18D07AB0B2 /* SessionConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionConnection.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -82,7 +108,12 @@
|
||||||
7607FF3804A2602B1C6A05D4 /* ResumeCursorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumeCursorTests.swift; sourceTree = "<group>"; };
|
7607FF3804A2602B1C6A05D4 /* ResumeCursorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumeCursorTests.swift; sourceTree = "<group>"; };
|
||||||
83446A0D895B866E880D4F2D /* DeviceTokenRegistrarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTokenRegistrarTests.swift; sourceTree = "<group>"; };
|
83446A0D895B866E880D4F2D /* DeviceTokenRegistrarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTokenRegistrarTests.swift; sourceTree = "<group>"; };
|
||||||
844A9C78194E7644A78FFA23 /* NotificationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationDelegate.swift; sourceTree = "<group>"; };
|
844A9C78194E7644A78FFA23 /* NotificationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
87407DA9C464BA9C9E118308 /* FaceIDGate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaceIDGate.swift; sourceTree = "<group>"; };
|
||||||
|
94525E2A804BF64F12806D4E /* LockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockView.swift; sourceTree = "<group>"; };
|
||||||
|
959878B4816DD2617038A339 /* SessionRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRegistry.swift; sourceTree = "<group>"; };
|
||||||
|
96A48B8A34A0647A8BF12B55 /* SettingsUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsUITests.swift; sourceTree = "<group>"; };
|
||||||
99FA0A0FD737901834AD5705 /* ThemeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeTests.swift; sourceTree = "<group>"; };
|
99FA0A0FD737901834AD5705 /* ThemeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeTests.swift; sourceTree = "<group>"; };
|
||||||
|
9E41A5D34EADEA9D2925DDF0 /* piRemoteUITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = piRemoteUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
A38B86E930CB34DEB9E4C144 /* PairingFlowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingFlowView.swift; sourceTree = "<group>"; };
|
A38B86E930CB34DEB9E4C144 /* PairingFlowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingFlowView.swift; sourceTree = "<group>"; };
|
||||||
A3F776605A4109C047E44A89 /* PasteSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteSheet.swift; sourceTree = "<group>"; };
|
A3F776605A4109C047E44A89 /* PasteSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteSheet.swift; sourceTree = "<group>"; };
|
||||||
A75BE928FA90D8AF2C56615D /* TerminalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalViewController.swift; sourceTree = "<group>"; };
|
A75BE928FA90D8AF2C56615D /* TerminalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalViewController.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -90,14 +121,21 @@
|
||||||
AFF032BC30D513204211ADA5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
AFF032BC30D513204211ADA5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
B772854E3FADA8998C93DAF5 /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = "<group>"; };
|
B772854E3FADA8998C93DAF5 /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = "<group>"; };
|
||||||
BC48E39D19238178A180B30C /* ThemeStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeStore.swift; sourceTree = "<group>"; };
|
BC48E39D19238178A180B30C /* ThemeStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeStore.swift; sourceTree = "<group>"; };
|
||||||
|
BEEC5B3171A29F91F7D9B67E /* PairingUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingUITests.swift; sourceTree = "<group>"; };
|
||||||
C5B05BBDD469F51657ED89B0 /* TerminalFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalFont.swift; sourceTree = "<group>"; };
|
C5B05BBDD469F51657ED89B0 /* TerminalFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalFont.swift; sourceTree = "<group>"; };
|
||||||
|
C5BCDE8061BF3E2DABEA12E7 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||||
C7961BE126AFEEE4B7AA6621 /* ResumeCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumeCursor.swift; sourceTree = "<group>"; };
|
C7961BE126AFEEE4B7AA6621 /* ResumeCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumeCursor.swift; sourceTree = "<group>"; };
|
||||||
C98EF1F714A1A5E8D4C3DA2B /* ScrollbackCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollbackCache.swift; sourceTree = "<group>"; };
|
C98EF1F714A1A5E8D4C3DA2B /* ScrollbackCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollbackCache.swift; sourceTree = "<group>"; };
|
||||||
CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = piRemoteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = piRemoteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D30D90D7888D84A2EF1B22EA /* StatusBarUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBarUITests.swift; sourceTree = "<group>"; };
|
||||||
D3FCCEE1BAA0983D83FC84DD /* SidecarCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidecarCredential.swift; sourceTree = "<group>"; };
|
D3FCCEE1BAA0983D83FC84DD /* SidecarCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidecarCredential.swift; sourceTree = "<group>"; };
|
||||||
DD8434E1D87FFE2616683652 /* ModifierState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierState.swift; sourceTree = "<group>"; };
|
DD8434E1D87FFE2616683652 /* ModifierState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierState.swift; sourceTree = "<group>"; };
|
||||||
|
DF52ADD110456E368EAE217C /* LockScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
E3A7FB4B9C4D2B63B016E11A /* TerminalTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalTheme.swift; sourceTree = "<group>"; };
|
E3A7FB4B9C4D2B63B016E11A /* TerminalTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalTheme.swift; sourceTree = "<group>"; };
|
||||||
|
E8C77FC9D24BB5F8DA96386C /* SessionSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionSwitcher.swift; sourceTree = "<group>"; };
|
||||||
E9BAF4FBE6CC23FDD9B40040 /* PairingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingTests.swift; sourceTree = "<group>"; };
|
E9BAF4FBE6CC23FDD9B40040 /* PairingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingTests.swift; sourceTree = "<group>"; };
|
||||||
|
ED280CEF6D334529433F20A3 /* SessionSwitcherUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionSwitcherUITests.swift; sourceTree = "<group>"; };
|
||||||
|
EE5E1A0BE69AF1FEF73E373F /* SmokeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmokeUITests.swift; sourceTree = "<group>"; };
|
||||||
F47CA5A1045A264958B360BF /* KeychainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainTests.swift; sourceTree = "<group>"; };
|
F47CA5A1045A264958B360BF /* KeychainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainTests.swift; sourceTree = "<group>"; };
|
||||||
F553E905D716538D9DA442E7 /* ModifierBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierBar.swift; sourceTree = "<group>"; };
|
F553E905D716538D9DA442E7 /* ModifierBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierBar.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
@ -120,6 +158,7 @@
|
||||||
children = (
|
children = (
|
||||||
2E2370A3190FDC144C822FF6 /* piRemote.app */,
|
2E2370A3190FDC144C822FF6 /* piRemote.app */,
|
||||||
CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */,
|
CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */,
|
||||||
|
9E41A5D34EADEA9D2925DDF0 /* piRemoteUITests.xctest */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -128,6 +167,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
67F95D26CD899B18D07AB0B2 /* SessionConnection.swift */,
|
67F95D26CD899B18D07AB0B2 /* SessionConnection.swift */,
|
||||||
|
959878B4816DD2617038A339 /* SessionRegistry.swift */,
|
||||||
);
|
);
|
||||||
path = Sessions;
|
path = Sessions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -144,6 +184,15 @@
|
||||||
path = Core;
|
path = Core;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
35F24B7F065B257F93810E5B /* Sessions */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
2C3C69D7879985E77A45DE76 /* SessionRow.swift */,
|
||||||
|
E8C77FC9D24BB5F8DA96386C /* SessionSwitcher.swift */,
|
||||||
|
);
|
||||||
|
path = Sessions;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
49209A78102230A37C0FF8D0 /* Terminal */ = {
|
49209A78102230A37C0FF8D0 /* Terminal */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -197,6 +246,7 @@
|
||||||
children = (
|
children = (
|
||||||
C8D95B3C16FEE9C9FBE38FDE /* Sources */,
|
C8D95B3C16FEE9C9FBE38FDE /* Sources */,
|
||||||
69990A9885FB5B354E73AB90 /* Tests */,
|
69990A9885FB5B354E73AB90 /* Tests */,
|
||||||
|
B259358DD628B98EC61A6736 /* UITests */,
|
||||||
161D89B853288EC766A0767D /* Products */,
|
161D89B853288EC766A0767D /* Products */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -211,6 +261,21 @@
|
||||||
path = Input;
|
path = Input;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
B259358DD628B98EC61A6736 /* UITests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5C1F7B03B47D7766D72BA3B8 /* Helpers.swift */,
|
||||||
|
DF52ADD110456E368EAE217C /* LockScreenUITests.swift */,
|
||||||
|
1E689590D75F152E90467016 /* ModifierBarUITests.swift */,
|
||||||
|
BEEC5B3171A29F91F7D9B67E /* PairingUITests.swift */,
|
||||||
|
ED280CEF6D334529433F20A3 /* SessionSwitcherUITests.swift */,
|
||||||
|
96A48B8A34A0647A8BF12B55 /* SettingsUITests.swift */,
|
||||||
|
EE5E1A0BE69AF1FEF73E373F /* SmokeUITests.swift */,
|
||||||
|
D30D90D7888D84A2EF1B22EA /* StatusBarUITests.swift */,
|
||||||
|
);
|
||||||
|
path = UITests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
C06242078CD1DD2BD7C7A4FA /* CoreTests */ = {
|
C06242078CD1DD2BD7C7A4FA /* CoreTests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -228,6 +293,14 @@
|
||||||
path = CoreTests;
|
path = CoreTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
C7FBB3C467939760D2971070 /* Status */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0C66962D8B5B6869B60F8101 /* StatusBar.swift */,
|
||||||
|
);
|
||||||
|
path = Status;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
C8D95B3C16FEE9C9FBE38FDE /* Sources */ = {
|
C8D95B3C16FEE9C9FBE38FDE /* Sources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -261,6 +334,9 @@
|
||||||
children = (
|
children = (
|
||||||
9DF960DFB90BF425282C35D0 /* Input */,
|
9DF960DFB90BF425282C35D0 /* Input */,
|
||||||
8A477F7D38B42EEB3F70323F /* Pairing */,
|
8A477F7D38B42EEB3F70323F /* Pairing */,
|
||||||
|
35F24B7F065B257F93810E5B /* Sessions */,
|
||||||
|
F681ED5F43C5283558361FAC /* Settings */,
|
||||||
|
C7FBB3C467939760D2971070 /* Status */,
|
||||||
49209A78102230A37C0FF8D0 /* Terminal */,
|
49209A78102230A37C0FF8D0 /* Terminal */,
|
||||||
);
|
);
|
||||||
path = UI;
|
path = UI;
|
||||||
|
|
@ -283,6 +359,7 @@
|
||||||
ED7AFC5C0EF365C5831C7245 /* Auth */ = {
|
ED7AFC5C0EF365C5831C7245 /* Auth */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
87407DA9C464BA9C9E118308 /* FaceIDGate.swift */,
|
||||||
B772854E3FADA8998C93DAF5 /* Keychain.swift */,
|
B772854E3FADA8998C93DAF5 /* Keychain.swift */,
|
||||||
0F544C25D53F52291E2FDB6F /* Pairing.swift */,
|
0F544C25D53F52291E2FDB6F /* Pairing.swift */,
|
||||||
D3FCCEE1BAA0983D83FC84DD /* SidecarCredential.swift */,
|
D3FCCEE1BAA0983D83FC84DD /* SidecarCredential.swift */,
|
||||||
|
|
@ -290,9 +367,36 @@
|
||||||
path = Auth;
|
path = Auth;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
F681ED5F43C5283558361FAC /* Settings */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
94525E2A804BF64F12806D4E /* LockView.swift */,
|
||||||
|
C5BCDE8061BF3E2DABEA12E7 /* SettingsView.swift */,
|
||||||
|
);
|
||||||
|
path = Settings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
2B14D5AC9C0B9175642D6460 /* piRemoteUITests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = FAF190D5257A3BA4C5F939C3 /* Build configuration list for PBXNativeTarget "piRemoteUITests" */;
|
||||||
|
buildPhases = (
|
||||||
|
6588DBB02A562A96AA88EE1A /* Sources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
94235F03119D91B660C7E290 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = piRemoteUITests;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = piRemoteUITests;
|
||||||
|
productReference = 9E41A5D34EADEA9D2925DDF0 /* piRemoteUITests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.ui-testing";
|
||||||
|
};
|
||||||
2C3DD20A67B90DDE04FDEE41 /* piRemoteTests */ = {
|
2C3DD20A67B90DDE04FDEE41 /* piRemoteTests */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = C553B125FB09A7C04D602AE2 /* Build configuration list for PBXNativeTarget "piRemoteTests" */;
|
buildConfigurationList = C553B125FB09A7C04D602AE2 /* Build configuration list for PBXNativeTarget "piRemoteTests" */;
|
||||||
|
|
@ -342,6 +446,11 @@
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
LastUpgradeCheck = 1640;
|
LastUpgradeCheck = 1640;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
|
2B14D5AC9C0B9175642D6460 = {
|
||||||
|
DevelopmentTeam = KNXX8R3648;
|
||||||
|
ProvisioningStyle = Automatic;
|
||||||
|
TestTargetID = 4910ACCEB67B73CBA3440774;
|
||||||
|
};
|
||||||
2C3DD20A67B90DDE04FDEE41 = {
|
2C3DD20A67B90DDE04FDEE41 = {
|
||||||
DevelopmentTeam = KNXX8R3648;
|
DevelopmentTeam = KNXX8R3648;
|
||||||
ProvisioningStyle = Automatic;
|
ProvisioningStyle = Automatic;
|
||||||
|
|
@ -372,6 +481,7 @@
|
||||||
targets = (
|
targets = (
|
||||||
4910ACCEB67B73CBA3440774 /* piRemote */,
|
4910ACCEB67B73CBA3440774 /* piRemote */,
|
||||||
2C3DD20A67B90DDE04FDEE41 /* piRemoteTests */,
|
2C3DD20A67B90DDE04FDEE41 /* piRemoteTests */,
|
||||||
|
2B14D5AC9C0B9175642D6460 /* piRemoteUITests */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
@ -405,9 +515,11 @@
|
||||||
734F2FECD358816F695D26CD /* AppState.swift in Sources */,
|
734F2FECD358816F695D26CD /* AppState.swift in Sources */,
|
||||||
F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */,
|
F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */,
|
||||||
909A26B85FA298A870E407CD /* DeviceTokenRegistrar.swift in Sources */,
|
909A26B85FA298A870E407CD /* DeviceTokenRegistrar.swift in Sources */,
|
||||||
|
9E4B31AA31D8A900D36918A3 /* FaceIDGate.swift in Sources */,
|
||||||
B3809456CF2E96F1B1B862C2 /* FontStore.swift in Sources */,
|
B3809456CF2E96F1B1B862C2 /* FontStore.swift in Sources */,
|
||||||
2AA3AC859917D32C1444FC5B /* FrameCodec.swift in Sources */,
|
2AA3AC859917D32C1444FC5B /* FrameCodec.swift in Sources */,
|
||||||
C776D609DB29E5B4C90881F9 /* Keychain.swift in Sources */,
|
C776D609DB29E5B4C90881F9 /* Keychain.swift in Sources */,
|
||||||
|
132F60783EC43AE420FA7CD5 /* LockView.swift in Sources */,
|
||||||
19E584DD72E8F6DE3AF4E77F /* MainTerminalView.swift in Sources */,
|
19E584DD72E8F6DE3AF4E77F /* MainTerminalView.swift in Sources */,
|
||||||
E9126D5D059DAD3717FA2398 /* ModifierBar.swift in Sources */,
|
E9126D5D059DAD3717FA2398 /* ModifierBar.swift in Sources */,
|
||||||
B8800C5E81FBB0C3CE9C6E7D /* ModifierState.swift in Sources */,
|
B8800C5E81FBB0C3CE9C6E7D /* ModifierState.swift in Sources */,
|
||||||
|
|
@ -419,7 +531,12 @@
|
||||||
09AC16350B4E83B71B05A9D5 /* ResumeCursor.swift in Sources */,
|
09AC16350B4E83B71B05A9D5 /* ResumeCursor.swift in Sources */,
|
||||||
9AC28FD7FD38F250FE477441 /* ScrollbackCache.swift in Sources */,
|
9AC28FD7FD38F250FE477441 /* ScrollbackCache.swift in Sources */,
|
||||||
1F353AB548615ECD7D241EF7 /* SessionConnection.swift in Sources */,
|
1F353AB548615ECD7D241EF7 /* SessionConnection.swift in Sources */,
|
||||||
|
6A52DBC5C2845ADA05B37A35 /* SessionRegistry.swift in Sources */,
|
||||||
|
C87E6CCFC4ADC4AC4CAC4C0D /* SessionRow.swift in Sources */,
|
||||||
|
4334301CFE20E6B66BDE7D19 /* SessionSwitcher.swift in Sources */,
|
||||||
|
A51AABE190B66EE994D8415B /* SettingsView.swift in Sources */,
|
||||||
2D8C05476A83F5CAB9A55A11 /* SidecarCredential.swift in Sources */,
|
2D8C05476A83F5CAB9A55A11 /* SidecarCredential.swift in Sources */,
|
||||||
|
D8F05ED47CD1A4A8298EDDFB /* StatusBar.swift in Sources */,
|
||||||
F8CBA52AE2CC3D8496361D45 /* TerminalFont.swift in Sources */,
|
F8CBA52AE2CC3D8496361D45 /* TerminalFont.swift in Sources */,
|
||||||
D3E8D6064F38E4024A6863C9 /* TerminalTheme.swift in Sources */,
|
D3E8D6064F38E4024A6863C9 /* TerminalTheme.swift in Sources */,
|
||||||
7BD37B4A99532FD542D21526 /* TerminalViewController.swift in Sources */,
|
7BD37B4A99532FD542D21526 /* TerminalViewController.swift in Sources */,
|
||||||
|
|
@ -430,6 +547,21 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
6588DBB02A562A96AA88EE1A /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
A1527F94754A9205576C317C /* Helpers.swift in Sources */,
|
||||||
|
17F996CE1F5CF3FF12E5C1AB /* LockScreenUITests.swift in Sources */,
|
||||||
|
9BDEBAD2C295FDD53946FB8C /* ModifierBarUITests.swift in Sources */,
|
||||||
|
AEAB8079223530B0437F3434 /* PairingUITests.swift in Sources */,
|
||||||
|
EF47351AD35418E508ED33C9 /* SessionSwitcherUITests.swift in Sources */,
|
||||||
|
EAF7C85B3223C503829028D3 /* SettingsUITests.swift in Sources */,
|
||||||
|
0572AF0EFE02ABD12CD5C584 /* SmokeUITests.swift in Sources */,
|
||||||
|
F10312EF88278BB719CCF7E7 /* StatusBarUITests.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
6DDDB771E08071591D668B0A /* Sources */ = {
|
6DDDB771E08071591D668B0A /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
|
@ -453,6 +585,11 @@
|
||||||
target = 4910ACCEB67B73CBA3440774 /* piRemote */;
|
target = 4910ACCEB67B73CBA3440774 /* piRemote */;
|
||||||
targetProxy = B301DDFED8092F66145718E3 /* PBXContainerItemProxy */;
|
targetProxy = B301DDFED8092F66145718E3 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
94235F03119D91B660C7E290 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 4910ACCEB67B73CBA3440774 /* piRemote */;
|
||||||
|
targetProxy = 4BC4CAFF5DFB43FCB5A72089 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
|
|
@ -653,6 +790,40 @@
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
CB33989104A2C99094B6896C /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "de.vpsj.pi-remote.uitests";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
TEST_TARGET_NAME = piRemote;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
F837F7618AB4341D74A53209 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "de.vpsj.pi-remote.uitests";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
TEST_TARGET_NAME = piRemote;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
|
|
@ -683,6 +854,15 @@
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Debug;
|
defaultConfigurationName = Debug;
|
||||||
};
|
};
|
||||||
|
FAF190D5257A3BA4C5F939C3 /* Build configuration list for PBXNativeTarget "piRemoteUITests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
CB33989104A2C99094B6896C /* Debug */,
|
||||||
|
F837F7618AB4341D74A53209 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Debug;
|
||||||
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCRemoteSwiftPackageReference section */
|
/* Begin XCRemoteSwiftPackageReference section */
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,17 @@
|
||||||
ReferencedContainer = "container:piRemote.xcodeproj">
|
ReferencedContainer = "container:piRemote.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "NO">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "2B14D5AC9C0B9175642D6460"
|
||||||
|
BuildableName = "piRemoteUITests.xctest"
|
||||||
|
BlueprintName = "piRemoteUITests"
|
||||||
|
ReferencedContainer = "container:piRemote.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
</Testables>
|
</Testables>
|
||||||
<CommandLineArguments>
|
<CommandLineArguments>
|
||||||
</CommandLineArguments>
|
</CommandLineArguments>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue