Files
Flaro/FlixyUITests/LayoutSnapshots.swift
T
ScarriffleandClaude Opus 5 fccec1217b Eigene Seitenleiste — überall dieselbe
Die System-Seitenleiste sitzt auf dem iPad als schwebende Fläche und auf dem
Mac angeklebt am Fensterrand. `preferredLayout = .overlap` ist die dafür
vorgesehene Bitte, und macOS verwirft sie stillschweigend — gemessen, nicht
vermutet.

Statt deshalb die ganze Navigation neu zu bauen, bleibt der `TabView` stehen
und verliert nur sein Kleid: `TabChromeSuppressor` blendet Seiten- und
Tableiste aus, gezeichnet wird darüber. Auswahl, ein eigener Navigationsstapel
je Eintrag, erhaltener Scrollstand beim Wechseln — all das macht weiter das
System. Dass das Ausblenden geht, war kein Ratschluss: derselbe Griff hatte die
Leiste vorher schon versuchsweise verschwinden lassen.

Neu sind `FlixySidebar` (schwebende Fläche mit eigenem Rand, Mediatheken
einklappbar, Konto unten) und `FlixyTopBar` (dieselben Einträge als Leiste
oben, Mediatheken als Menü, weil oben der Platz waagerecht begrenzt ist). Das
iPhone bleibt beim System: dort gibt es keine Seitenleiste, sondern die Leiste
unten, und die ist überall dieselbe.

Der Platz für die Leiste ist ein **Sicherheitsrand**, kein Abstand, und er
hängt je Bildschirm — weder `TabView` noch `NavigationStack` reichen ihn an
ihren Inhalt weiter. Damit bleibt eine Reihe fensterbreit und schiebt ihre
Kacheln beim Wischen hinter die Leiste, stellt aber im Ruhezustand keine
dorthin. Der Aufmacher darf über seinen Bereich hinaus; das `.clipped()` im
Karussell musste dafür weichen, es schnitt genau das ab.

Noch nicht dabei: „Bearbeiten" mit Ziehen und Ein-/Ausblenden. Die Einträge
stehen in fester Reihenfolge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 19:17:27 +02:00

88 lines
3.7 KiB
Swift

import XCTest
/// Fährt die App in die Zustände, über die geredet wird, und legt Bilder davon ab.
///
/// Der Grund für diese Datei ist ein wiederkehrender Fehler: Aussagen über das
/// Aussehen waren Vermutungen, weil niemand hinsehen konnte. Der Simulator
/// kennt keinen Befehl fürs Antippen, und dieses Xcode bringt kein
/// Simulator-Fenster mehr mit, das sich fernsteuern ließe. Ein UI-Test kann
/// beides — tippen und fotografieren.
///
/// Die Bilder landen im Dokumentenordner des Testläufers, der vom Rechner aus
/// über `simctl get_app_container` erreichbar ist. Anhänge im Ergebnisbündel
/// wären der vorgesehene Weg, müssten aber erst wieder herausgeschält werden.
///
/// Die Inhalte kommen aus `Tools/JellyfinStub` — kein echter Server, kein
/// echtes Konto, kein echter Token.
final class LayoutSnapshots: XCTestCase {
override func setUp() {
continueAfterFailure = false
}
/// `XCUIScreen` fotografiert in der Lage des **Geräts**, nicht in der der
/// Oberfläche — im Querformat kommt das Bild dann hochkant und um
/// neunzig Grad gedreht heraus, und jedes Maß daran ist falsch herum.
/// Die App selbst fotografiert richtig herum.
private func shoot(_ app: XCUIApplication, _ name: String) {
let data = app.screenshot().pngRepresentation
let folder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
try? data.write(to: folder.appendingPathComponent("\(name).png"))
}
/// Das Umschalten zwischen Seitenleiste und Leiste oben.
///
/// Beim Umschalten steht die Leiste kurz falsch, bevor sie sich fängt.
/// Fotografiert wird in Serie, weil genau der Zwischenzustand gesucht ist
/// und ein einzelnes Bild danach nichts zeigt.
func testSidebarToggle() throws {
let app = XCUIApplication()
app.launchArguments = ["-FlixyStubServer", "http://127.0.0.1:8096"]
app.launch()
XCUIDevice.shared.orientation = .landscapeLeft
XCTAssertTrue(app.staticTexts["Weiterschauen"].waitForExistence(timeout: 20))
Thread.sleep(forTimeInterval: 2)
shoot(app, "10-seitenleiste")
// Über die Beschriftung gesucht, nicht über die Stellung: „der zweite
// Knopf" war einmal der Umschalter und nach einem Umbau die Kontozeile,
// und der Test öffnete fortan das Kontomenü.
let toggle = app.buttons["Navigation nach oben"]
XCTAssertTrue(toggle.waitForExistence(timeout: 5))
toggle.tap()
for step in 0..<8 {
shoot(app, String(format: "11-umschalten-%d", step))
Thread.sleep(forTimeInterval: 0.1)
}
Thread.sleep(forTimeInterval: 2)
shoot(app, "12-oben")
}
func testHomeAndDetail() throws {
let app = XCUIApplication()
app.launchArguments = ["-FlixyStubServer", "http://127.0.0.1:8096"]
app.launch()
XCUIDevice.shared.orientation = .landscapeLeft
// Die Startseite muss stehen, bevor fotografiert wird — sonst ist auf
// dem Bild nur der Ladekreis.
XCTAssertTrue(app.staticTexts["Weiterschauen"].waitForExistence(timeout: 20))
Thread.sleep(forTimeInterval: 3)
shoot(app, "01-start-oben")
// Der Aufmacher wechselt nach sieben Sekunden. Kurz davor anfangen
// und in Serie fotografieren: nur so ist der Übergang selbst zu sehen
// und nicht bloß sein Ergebnis.
Thread.sleep(forTimeInterval: 4.2)
for step in 0..<6 {
shoot(app, String(format: "02-wechsel-%d", step))
Thread.sleep(forTimeInterval: 0.12)
}
Thread.sleep(forTimeInterval: 2)
shoot(app, "03-danach")
}
}