import XCTest @testable import SaplingEditor #if os(macOS) import AppKit @MainActor final class HybridMarkdownLiveEditorHarnessTests: XCTestCase { func testLiveInitialFirstResponderDoesNotShowHeadingSourceBeforeUserInteraction() { let harness = HybridMarkdownLiveEditorHarness(source: "# Heading\nParagraph") harness.simulateLaunchFirstResponder() XCTAssertTrue(harness.headingMarkerIsHidden()) } func testLiveParagraphGeometryReturnsAfterClickAndFocusAway() throws { let source = """ # Heading Paragraph with **bold**, *italic*, `code`, and [Link](https://example.com) markers. Outro """ let harness = HybridMarkdownLiveEditorHarness(source: source) harness.simulateLaunchFirstResponder() let initialPoint = try XCTUnwrap(harness.point(for: "Paragraph")) let paragraphLocation = (source as NSString).range(of: "bold").location harness.setSelection(NSRange(location: paragraphLocation, length: 0)) harness.simulateFocusAway() let finalPoint = try XCTUnwrap(harness.point(for: "Paragraph")) XCTAssertEqual(initialPoint.x, finalPoint.x, accuracy: 0.001) XCTAssertEqual(initialPoint.y, finalPoint.y, accuracy: 0.001) } func testLiveCheckboxClickPreservesSelectionActiveLineAndGeometry() throws { let source = "Editing here\n* [ ] Move with arrow keys." let editingRange = (source as NSString).range(of: "Editing") let harness = HybridMarkdownLiveEditorHarness( source: source, selectedRange: NSRange(location: editingRange.location, length: 0) ) harness.simulateLaunchFirstResponder() harness.setSelection(NSRange(location: editingRange.location, length: 0)) let selectionBefore = harness.selectedRange() let activeLineBefore = harness.effectiveActiveLineIndex() let labelPointBefore = try XCTUnwrap(harness.point(for: "Move")) let checkboxFrameBefore = try XCTUnwrap(harness.checklistButtonFrame(lineIndex: 1)) harness.clickRenderedCheckbox(lineIndex: 1) let labelPointAfter = try XCTUnwrap(harness.point(for: "Move")) let checkboxFrameAfter = try XCTUnwrap(harness.checklistButtonFrame(lineIndex: 1)) XCTAssertEqual(harness.selectedRange(), selectionBefore) XCTAssertEqual(harness.effectiveActiveLineIndex(), activeLineBefore) XCTAssertTrue(harness.source().contains("* [x] Move with arrow keys.")) XCTAssertEqual(labelPointBefore.x, labelPointAfter.x, accuracy: 0.001) XCTAssertEqual(labelPointBefore.y, labelPointAfter.y, accuracy: 0.001) XCTAssertEqual(checkboxFrameBefore.origin.x, checkboxFrameAfter.origin.x, accuracy: 0.001) XCTAssertEqual(checkboxFrameBefore.origin.y, checkboxFrameAfter.origin.y, accuracy: 0.001) XCTAssertEqual(checkboxFrameBefore.size.width, checkboxFrameAfter.size.width, accuracy: 0.001) XCTAssertEqual(checkboxFrameBefore.size.height, checkboxFrameAfter.size.height, accuracy: 0.001) } func testInitialChecklistOverlayTracksFirstLiveLayoutPass() throws { let source = """ ## Navigation Checklist Use this section for quick keyboard testing. * [ ] Move with arrow keys. * [ ] Jump by word with Option + Arrow. * [ ] Extend selection with Shift + Arrow. * [ ] Select across multiple lines. * [ ] Use Home, End, Page Up, and Page Down. * [ ] Type into the active line after moving quickly. """ let harness = HybridMarkdownLiveEditorHarness(source: source, initialWidth: 640) let initialGaps = try Dictionary(uniqueKeysWithValues: (4...9).map { lineIndex in (lineIndex, try XCTUnwrap(harness.checklistLabelGap(lineIndex: lineIndex))) }) harness.simulateLayout(width: 900) for lineIndex in 4...9 { let alignmentDelta = try XCTUnwrap(harness.checklistAlignmentDelta(lineIndex: lineIndex)) let labelGap = try XCTUnwrap(harness.checklistLabelGap(lineIndex: lineIndex)) XCTAssertLessThan(alignmentDelta, 8, "Checklist overlay for line \(lineIndex) is not aligned with its label") XCTAssertEqual( labelGap, initialGaps[lineIndex] ?? labelGap, accuracy: 0.001, "Checklist overlay for line \(lineIndex) did not track the label through the first layout pass" ) } } } #endif