Files
TUIkit/Tests/TUIkitTests/ComponentViewTests.swift
T
phranck f4141d0ecf Test: Strengthen 17 weak test assertions
Replace vague assertions with concrete, specific checks:

**Pattern 1: !buffer.isEmpty → Specific content checks**
- ViewTests.swift (1): Check bold ANSI code + content
- StatusBarTests.swift (4): Check item labels present
- ModifierTests.swift (1): Check border characters
- ButtonTests.swift (3): Check height + border characters
- ComponentViewTests.swift (4): Check titles + content
- ContainerViewTests.swift (1): Check height + content
- FrameBufferTests.swift (2): Check overlay composition

**Pattern 2: Weak contains() → Exact ANSI codes**
- ANSIRendererFullTests.swift (1): contains("1") → contains("\u{1B}[1m")

**Summary:**
- 17 tests strengthened across 8 files
- All tests now assert observable behavior
- No property readback, no empty checks
- 412 tests passing

Addresses to-dos.md line 34: "Weak Test Rewrites"
2026-02-01 22:00:22 +01:00

219 lines
6.0 KiB
Swift

//
// ComponentViewTests.swift
// TUIkit
//
// Tests for Box, Card, Panel, ContainerConfig, ContainerView, and ForEach views.
//
import Testing
@testable import TUIkit
// MARK: - Test Helpers
/// Creates a default render context for testing.
private func testContext(width: Int = 40, height: Int = 24) -> RenderContext {
RenderContext(availableWidth: width, availableHeight: height)
}
// MARK: - Box Tests
@Suite("Box Tests")
struct BoxTests {
@Test("Box renders with border around content")
func boxRendersWithBorder() {
let box = Box(.line) {
Text("Hi")
}
let context = testContext()
let buffer = renderToBuffer(box, context: context)
// Box = border top + content + border bottom = 3 lines minimum
#expect(buffer.height >= 3)
// Width = content width + 2 (left + right border)
#expect(buffer.width >= 4) // "Hi" (2) + borders (2)
}
@Test("Box renders empty content")
func boxEmptyContent() {
let box = Box(.line) {
EmptyView()
}
let context = testContext()
let buffer = renderToBuffer(box, context: context)
// EmptyView produces empty buffer, so bordered empty = empty
#expect(buffer.isEmpty)
}
@Test("Box with multiple children renders vertically")
func boxMultipleChildren() {
let box = Box(.line) {
Text("Line 1")
Text("Line 2")
}
let context = testContext()
let buffer = renderToBuffer(box, context: context)
// Top border + 2 content lines + bottom border = 4
#expect(buffer.height >= 4)
}
@Test("Box delegates to body (is composite, not Renderable)")
func boxIsComposite() {
let box = Box {
Text("Test")
}
// Box should NOT conform to Renderable — it uses body
#expect(!(box is Renderable))
}
}
// MARK: - Card Tests
@Suite("Card Tests")
struct CardTests {
@Test("Card renders with border")
func cardRenders() {
let card = Card(title: "Test") {
Text("Hello")
}
let context = testContext()
let buffer = card.renderToBuffer(context: context)
// Should have top border + content + bottom border
#expect(buffer.height >= 3)
let allContent = buffer.lines.joined()
#expect(allContent.contains("Hello"))
#expect(allContent.contains("Test")) // title
}
@Test("Card without title renders")
func cardNoTitleRenders() {
let card = Card {
Text("Content")
}
let context = testContext()
let buffer = card.renderToBuffer(context: context)
#expect(buffer.height >= 3)
let allContent = buffer.lines.joined()
#expect(allContent.contains("Content"))
}
@Test("Card with footer is taller than without")
func cardFooterAddsHeight() {
let cardWithout = Card(title: "Test") {
Text("Body")
}
let cardWith = Card(title: "Test") {
Text("Body")
} footer: {
Text("Footer")
}
let context = testContext()
let bufferWithout = cardWithout.renderToBuffer(context: context)
let bufferWith = cardWith.renderToBuffer(context: context)
#expect(bufferWith.height > bufferWithout.height)
}
}
// MARK: - Panel Tests
@Suite("Panel Tests")
struct PanelTests {
@Test("Panel renders with border and title")
func panelRenders() {
let panel = Panel("Test Panel") {
Text("Hello")
}
let context = testContext()
let buffer = panel.renderToBuffer(context: context)
// Top border (with title) + content + bottom border
#expect(buffer.height >= 3)
let allContent = buffer.lines.joined()
#expect(allContent.contains("Test Panel")) // title
#expect(allContent.contains("Hello"))
}
@Test("Panel with footer is taller")
func panelFooterAddsHeight() {
let panelWithout = Panel("Test") {
Text("Body")
}
let panelWith = Panel("Test") {
Text("Body")
} footer: {
Text("Footer")
}
let context = testContext()
let bufferWithout = panelWithout.renderToBuffer(context: context)
let bufferWith = panelWith.renderToBuffer(context: context)
#expect(bufferWith.height > bufferWithout.height)
}
}
// MARK: - ContainerView Tests
@Suite("ContainerView Direct Tests")
struct ContainerViewDirectTests {
@Test("ContainerView renders with border")
func containerViewRenders() {
let container = ContainerView(title: "Test") {
Text("Content")
}
let context = testContext()
let buffer = container.renderToBuffer(context: context)
#expect(buffer.height >= 3)
let allContent = buffer.lines.joined()
#expect(allContent.contains("Test")) // title
#expect(allContent.contains("Content"))
}
}
// MARK: - ForEach Tests
@Suite("ForEach Tests")
struct ForEachTests {
struct TestItem: Identifiable {
let id: String
let name: String
}
@Test("ForEach generates correct number of views")
func forEachViewGeneration() {
let items = [TestItem(id: "a", name: "Alpha"), TestItem(id: "b", name: "Beta")]
let forEach = ForEach(items) { item in
Text(item.name)
}
// Verify content closure works
var generatedTexts: [String] = []
for item in forEach.data {
let view = forEach.content(item)
generatedTexts.append(view.content)
}
#expect(generatedTexts == ["Alpha", "Beta"])
}
// NOTE: ForEach inside VStack/HStack cannot be tested via renderToBuffer
// directly. ForEach is flattened into ViewArray by @ViewBuilder.buildArray
// at compile time — not at render time. Direct construction in tests
// bypasses the builder, so ForEach remains unflattened and produces
// an empty buffer. This is expected behavior, matching SwiftUI's pattern.
}