Files
conjure/Tests/ConjureKitTests/LauncherPositionTests.swift

77 lines
3.9 KiB
Swift

import AppKit
import ConjureKit
import Testing
@testable import Conjure
@Test @MainActor
func launcherPositionKeepsTheDraggedCenterAcrossCommandsSizesAndRelaunch() throws {
_ = NSApplication.shared
let suite = "LauncherPosition.\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
let directory = FileManager.default.temporaryDirectory.appendingPathComponent(suite)
defer {
defaults.removePersistentDomain(forName: suite)
try? FileManager.default.removeItem(at: directory)
}
func makeLauncher() -> LauncherWindowController {
LauncherWindowController(
history: LaunchHistory(defaults: defaults, now: { Date(timeIntervalSinceReferenceDate: 12_000) }),
defaults: defaults, notesDirectory: directory)
}
func center(_ frame: CGRect) -> CGPoint { CGPoint(x: frame.midX, y: frame.midY) }
let launcher = makeLauncher()
let window = try #require(launcher.window as? LauncherWindow)
defer { launcher.dismiss(restoringFocus: false) }
let display = try #require(window.screen).visibleFrame
let initialCenter = CGPoint(x: display.midX.rounded(.down), y: display.midY.rounded(.down))
window.setFrameOrigin(CGPoint(x: initialCenter.x - window.frame.width / 2,
y: initialCenter.y - window.frame.height / 2))
// Open from the launcher rather than presenting again (which restores the saved position).
func descendants(_ view: NSView) -> [NSView] { [view] + view.subviews.flatMap(descendants) }
let content = try #require(window.contentView)
let search = try #require(descendants(content).compactMap { $0 as? NSSearchField }.first)
search.stringValue = "notes"
launcher.controlTextDidChange(Notification(name: NSControl.textDidChangeNotification, object: search))
#expect(launcher.control(search, textView: NSTextView(), doCommandBy: #selector(NSResponder.insertNewline(_:))))
try #require(center(window.frame) == initialCenter)
let draggedCenter = CGPoint(x: initialCenter.x + 30, y: initialCenter.y - 20)
window.setFrameOrigin(CGPoint(x: draggedCenter.x - window.frame.width / 2,
y: draggedCenter.y - window.frame.height / 2))
window.dragEnded?()
// Back must use the moved Notes center, not the launcher frame captured on entry.
let back = try #require(descendants(content).compactMap { $0 as? NSButton }.first {
$0.accessibilityLabel() == "Back to applications"
})
back.performClick(nil)
#expect(center(window.frame) == draggedCenter)
for command: Application.Command in [.emoji, .translate, .notes] {
launcher.present(command: command)
#expect(center(window.frame) == draggedCenter)
}
var resized = window.frame
resized.size = CGSize(width: 620, height: 330)
resized.origin = CGPoint(x: draggedCenter.x - resized.width / 2, y: draggedCenter.y - resized.height / 2)
window.setFrame(resized, display: true)
window.dragEnded?()
launcher.dismiss(restoringFocus: false)
let reopened = makeLauncher()
defer { reopened.dismiss(restoringFocus: false) }
for command: Application.Command in [.notes, .emoji, .translate] {
reopened.present(command: command)
#expect(center(try #require(reopened.window).frame) == draggedCenter)
}
// A compact Notes window can fit where the hidden launcher-sized frame cannot.
reopened.present(command: .notes)
let reopenedWindow = try #require(reopened.window as? LauncherWindow)
let edgeCenter = CGPoint(x: display.minX + 320, y: initialCenter.y)
reopenedWindow.setFrameOrigin(CGPoint(x: edgeCenter.x - reopenedWindow.frame.width / 2,
y: edgeCenter.y - reopenedWindow.frame.height / 2))
reopenedWindow.dragEnded?()
reopened.dismiss(restoringFocus: false)
reopened.present(command: .notes)
#expect(center(reopenedWindow.frame) == edgeCenter)
}