Files
TUIkit/Tests/TUIkitTests/AlertPresentationModifierTests.swift
T
phranck ac5e63eb84 Feat: Add ButtonRole, horizontal Alert buttons, ESC dismiss, arrow key navigation
- Add ButtonRole (.cancel, .destructive) with SwiftUI-conformant API
- Alert renders buttons horizontally, sorted by role (cancel left)
- Alert max width capped at 60 characters for readability
- ESC key dismisses alerts via AlertPresentationModifier handler
- FocusManager: Left/Right arrows navigate within sections (like Up/Down)
- Move completed plans to done/ directory
- Update example pages with minor adjustments
2026-02-08 23:00:59 +01:00

145 lines
4.7 KiB
Swift

// 🖥️ TUIKit — Terminal UI Kit for Swift
// AlertPresentationModifierTests.swift
//
// Created by LAYERED.work
// License: MIT dimming, centering, and alert rendering.
//
import Testing
@testable import TUIkit
@MainActor
@Suite("AlertPresentationModifier Tests")
struct AlertPresentationModifierTests {
/// Helper to create a RenderContext with default test settings.
private func testContext() -> RenderContext {
RenderContext(
availableWidth: 80,
availableHeight: 24,
tuiContext: TUIContext()
)
}
/// Helper to render a view to a FrameBuffer.
private func render<V: View>(_ view: V) -> FrameBuffer {
renderToBuffer(view, context: testContext())
}
@Test("Alert not presented shows only base content")
func notPresentedShowsBase() {
let isPresented = Binding.constant(false)
let view = Text("Base Content")
.alert("Title", isPresented: isPresented, actions: { EmptyView() }, message: { Text("Message") })
let buffer = render(view)
let content = buffer.lines.joined(separator: "\n").stripped
#expect(content.contains("Base Content"))
#expect(!content.contains("Title"))
#expect(!content.contains("Message"))
}
@Test("Alert presented shows dimmed base with alert overlay")
func presentedShowsAlert() {
let isPresented = Binding.constant(true)
let view = VStack {
Text("Base Content")
Text("More base text")
}
.alert("Alert Title", isPresented: isPresented, actions: { EmptyView() }, message: { Text("Alert Message") })
let buffer = render(view)
// Alert content should be present
let stripped = buffer.lines.joined(separator: "\n").stripped
#expect(stripped.contains("Alert Title"))
#expect(stripped.contains("Alert Message"))
// At least some content should have dim codes (from dimmed base)
// The dimmed modifier wraps content, so check for dim in raw output
let rawContent = buffer.lines.joined(separator: "\n")
#expect(rawContent.contains("\u{1B}[")) // Contains ANSI codes
}
@Test("Alert with actions renders action buttons")
func alertWithActions() {
let isPresented = Binding.constant(true)
let view = Text("Base")
.alert("Warning", isPresented: isPresented, actions: {
Button("Yes") { }
Button("No") { }
}, message: { Text("Are you sure?") })
let buffer = render(view)
let content = buffer.lines.joined(separator: "\n").stripped
#expect(content.contains("Warning"))
#expect(content.contains("Are you sure?"))
#expect(content.contains("Yes"))
#expect(content.contains("No"))
}
@Test("Alert without message renders title and actions only")
func alertWithoutMessage() {
let isPresented = Binding.constant(true)
let view = Text("Base")
.alert("Just Title", isPresented: isPresented, actions: {
Button("OK") { }
})
let buffer = render(view)
let content = buffer.lines.joined(separator: "\n").stripped
#expect(content.contains("Just Title"))
#expect(content.contains("OK"))
}
@Test("Alert respects custom colors")
func customColors() {
let isPresented = Binding.constant(true)
let view = Text("Base")
.alert(
"Custom",
isPresented: isPresented,
actions: { EmptyView() },
message: { Text("Message") },
borderColor: .red,
titleColor: .yellow
)
let buffer = render(view)
let content = buffer.lines.joined(separator: "\n")
// Should contain ANSI color codes (non-empty buffer with styling)
#expect(!buffer.isEmpty)
#expect(content.contains("\u{1B}["))
}
@Test("Toggle isPresented switches between states")
func togglePresentation() {
@State var showAlert = false
let view1 = Text("Content")
.alert("Alert", isPresented: $showAlert, actions: { EmptyView() }, message: { Text("Test") })
let buffer1 = render(view1)
let content1 = buffer1.lines.joined(separator: "\n").stripped
// Initially not shown
#expect(!content1.contains("Alert"))
// Toggle to show
showAlert = true
let view2 = Text("Content")
.alert("Alert", isPresented: $showAlert, actions: { EmptyView() }, message: { Text("Test") })
let buffer2 = render(view2)
let content2 = buffer2.lines.joined(separator: "\n").stripped
// Now shown
#expect(content2.contains("Alert"))
}
}