154 lines
7.1 KiB
Swift
154 lines
7.1 KiB
Swift
import AppKit
|
|
import ConjureKit
|
|
import Testing
|
|
@testable import Conjure
|
|
|
|
@Test @MainActor func emojiPickerNavigatesCopiesAndRemembersRecentSelections() throws {
|
|
_ = NSApplication.shared
|
|
let suite = "ConjureEmoji.\(UUID().uuidString)"
|
|
let defaults = UserDefaults(suiteName: suite)!
|
|
let pasteboard = NSPasteboard.withUniqueName()
|
|
defer {
|
|
defaults.removePersistentDomain(forName: suite)
|
|
pasteboard.releaseGlobally()
|
|
}
|
|
var query = "face"
|
|
var closed = false
|
|
var pasteRequests = 0
|
|
let picker = EmojiPickerController(defaults: defaults, pasteboard: pasteboard)
|
|
picker.input = { query }
|
|
picker.closed = { closed = true }
|
|
picker.pasteRequested = {
|
|
#expect(closed)
|
|
#expect(pasteboard.string(forType: .string) == EmojiCatalog.search(query)[1].value)
|
|
pasteRequests += 1
|
|
}
|
|
_ = picker.view
|
|
let matches = EmojiCatalog.search(query)
|
|
#expect(picker.handle(#selector(NSResponder.moveRight(_:))))
|
|
#expect(picker.handle(#selector(NSResponder.insertNewline(_:))))
|
|
#expect(pasteboard.string(forType: .string) == matches[1].value)
|
|
#expect(closed)
|
|
#expect(pasteRequests == 1)
|
|
#expect(defaults.stringArray(forKey: "recentEmoji") == [matches[1].value])
|
|
|
|
closed = false
|
|
query = "no-such-emoji"
|
|
picker.inputChanged()
|
|
picker.copyAndPasteSelection()
|
|
#expect(!closed)
|
|
#expect(pasteboard.string(forType: .string) == matches[1].value)
|
|
#expect(pasteRequests == 1)
|
|
query = "👩💻"
|
|
picker.inputChanged()
|
|
picker.copySelection()
|
|
#expect(pasteboard.string(forType: .string) == "👩💻")
|
|
#expect(pasteRequests == 1)
|
|
|
|
let reopened = EmojiPickerController(defaults: defaults, pasteboard: pasteboard)
|
|
_ = reopened.view
|
|
reopened.copySelection()
|
|
#expect(pasteboard.string(forType: .string) == "👩💻")
|
|
#expect(defaults.stringArray(forKey: "recentEmoji") == ["👩💻", matches[1].value])
|
|
}
|
|
|
|
@Test @MainActor func emojiActionsDefaultToPasteAndKeepCopyOnlyAvailable() throws {
|
|
_ = NSApplication.shared
|
|
let suite = "ConjureEmojiActions.\(UUID().uuidString)"
|
|
let defaults = UserDefaults(suiteName: suite)!
|
|
let pasteboard = NSPasteboard.withUniqueName()
|
|
defer { defaults.removePersistentDomain(forName: suite); pasteboard.releaseGlobally() }
|
|
let picker = EmojiPickerController(defaults: defaults, pasteboard: pasteboard)
|
|
picker.input = { "👩💻" }
|
|
var pasteRequests = 0
|
|
picker.pasteRequested = { pasteRequests += 1 }
|
|
let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 750, height: 400),
|
|
styleMask: [.borderless], backing: .buffered, defer: false)
|
|
window.contentView = picker.view
|
|
picker.showActions()
|
|
#expect(picker.handle(#selector(NSResponder.insertNewline(_:))))
|
|
#expect(pasteboard.string(forType: .string) == "👩💻")
|
|
#expect(pasteRequests == 1)
|
|
|
|
pasteboard.clearContents()
|
|
picker.showActions()
|
|
#expect(picker.handle(#selector(NSResponder.moveDown(_:))))
|
|
#expect(picker.handle(#selector(NSResponder.insertNewline(_:))))
|
|
#expect(pasteboard.string(forType: .string) == "👩💻")
|
|
#expect(pasteRequests == 1)
|
|
|
|
picker.showActions()
|
|
#expect(picker.handle(#selector(NSResponder.moveDown(_:))))
|
|
#expect(picker.handle(#selector(NSResponder.moveDown(_:))))
|
|
#expect(picker.handle(#selector(NSResponder.insertNewline(_:))))
|
|
#expect(defaults.stringArray(forKey: "favoriteEmoji") == ["👩💻"])
|
|
#expect(pasteRequests == 1)
|
|
}
|
|
|
|
@Test @MainActor func emojiCommandRestoresLauncherSearchOnEscape() throws {
|
|
_ = NSApplication.shared
|
|
let suite = "ConjureEmojiCommand.\(UUID().uuidString)"
|
|
let defaults = UserDefaults(suiteName: suite)!
|
|
defer { defaults.removePersistentDomain(forName: suite) }
|
|
let history = LaunchHistory(defaults: defaults, now: { Date(timeIntervalSinceReferenceDate: 12_000) })
|
|
let launcher = LauncherWindowController(history: history)
|
|
let content = try #require(launcher.window?.contentView)
|
|
func descendants(_ view: NSView) -> [NSView] { [view] + view.subviews.flatMap(descendants) }
|
|
let search = try #require(descendants(content).compactMap { $0 as? NSSearchField }.first)
|
|
search.stringValue = "emoji"
|
|
launcher.controlTextDidChange(Notification(name: NSControl.textDidChangeNotification, object: search))
|
|
_ = launcher.control(search, textView: NSTextView(), doCommandBy: #selector(NSResponder.insertNewline(_:)))
|
|
let grid = try #require(descendants(content).compactMap { $0 as? NSCollectionView }.first)
|
|
search.stringValue = ":woman_technologist:"
|
|
launcher.controlTextDidChange(Notification(name: NSControl.textDidChangeNotification, object: search))
|
|
#expect(grid.numberOfItems(inSection: 0) == 1)
|
|
#expect((grid.dataSource?.collectionView(grid, itemForRepresentedObjectAt: IndexPath(item: 0, section: 0)).view as? NSButton)?.title == "👩💻")
|
|
_ = launcher.control(search, textView: NSTextView(), doCommandBy: #selector(NSResponder.cancelOperation(_:)))
|
|
#expect(!descendants(content).contains { $0 === grid })
|
|
#expect(search.stringValue == "emoji")
|
|
let table = try #require(descendants(content).compactMap { $0 as? NSTableView }.first)
|
|
#expect(table.numberOfRows == 1)
|
|
}
|
|
|
|
@Test @MainActor func emojiFavoritesPersistAndNavigationCrossesTheSpacingBreak() throws {
|
|
_ = NSApplication.shared
|
|
let suite = "ConjureEmojiFavorites.\(UUID().uuidString)"
|
|
let defaults = UserDefaults(suiteName: suite)!
|
|
let pasteboard = NSPasteboard.withUniqueName()
|
|
defer { defaults.removePersistentDomain(forName: suite); pasteboard.releaseGlobally() }
|
|
var query = "👩💻"
|
|
let picker = EmojiPickerController(defaults: defaults, pasteboard: pasteboard)
|
|
picker.input = { query }
|
|
picker.view.frame = NSRect(x: 0, y: 0, width: 750, height: 400)
|
|
picker.toggleFavorite()
|
|
#expect(defaults.stringArray(forKey: "favoriteEmoji") == ["👩💻"])
|
|
query = ""
|
|
picker.inputChanged()
|
|
picker.view.layoutSubtreeIfNeeded()
|
|
let grid = try #require(picker.view.subviews.compactMap { $0 as? NSScrollView }.first?.documentView as? NSCollectionView)
|
|
#expect(grid.numberOfSections == 2)
|
|
#expect(grid.numberOfItems(inSection: 0) == 1)
|
|
#expect(picker.handleControlKey("j"))
|
|
picker.copySelection()
|
|
#expect(pasteboard.string(forType: .string) == EmojiCatalog.all[0].value)
|
|
#expect(picker.handleControlKey("k"))
|
|
picker.copySelection()
|
|
#expect(pasteboard.string(forType: .string) == "👩💻")
|
|
#expect(picker.handleControlKey("l"))
|
|
#expect(picker.handleControlKey("l"))
|
|
#expect(picker.handleControlKey("h"))
|
|
picker.copySelection()
|
|
#expect(pasteboard.string(forType: .string) == EmojiCatalog.all[0].value)
|
|
#expect(picker.handleControlKey("k"))
|
|
picker.toggleFavorite()
|
|
#expect(defaults.stringArray(forKey: "favoriteEmoji") == [])
|
|
#expect(grid.numberOfSections == 1)
|
|
query = "👩💻"
|
|
picker.inputChanged()
|
|
picker.toggleFavorite()
|
|
let reopened = EmojiPickerController(defaults: defaults, pasteboard: pasteboard)
|
|
_ = reopened.view
|
|
reopened.copySelection()
|
|
#expect(pasteboard.string(forType: .string) == "👩💻")
|
|
}
|