Files
Termind/TFMTests/TerminalContextMenuTests.swift

94 lines
4.2 KiB
Swift

// SPDX-FileCopyrightText: 2026 Kaede Akino
// SPDX-License-Identifier: GPL-3.0-only
import AppKit
import TermindPresentation
import Testing
@testable import Termind
@Suite @MainActor
struct TerminalContextMenuTests {
@Test func uploadActionAppearsOnlyWhenBoundAndUsesLiveAvailability() throws {
let view = TermindTerminalView(frame: .zero)
let title = String(localized: AppStrings.Terminal.uploadFile)
#expect(view.selectionContextMenu().item(withTitle: title) == nil)
var available = false
var requests = 0
view.uploadFiles = { requests += 1 }
view.canUploadFiles = { available }
#expect(view.selectionContextMenu().item(withTitle: title)?.isEnabled == false)
available = true
let item = try #require(view.selectionContextMenu().item(withTitle: title))
#expect(item.isEnabled)
_ = view.perform(item.action, with: item)
#expect(requests == 1)
available = false
_ = view.perform(item.action, with: item)
#expect(requests == 1)
}
@Test func oldPaneTeardownCannotRemoveOrDisableTheReplacementUploadMenu() throws {
let owner = PersistentTerminalViewOwner(write: { _, _ in }, resize: { _ in })
let mount = TerminalMountView(frame: .zero)
owner.mount(in: mount, state: owner.state, isVisible: false, requestsFocus: false)
defer { owner.unmount(from: mount) }
let view = try #require(mount.subviews.first as? TermindTerminalView)
let oldBinding = owner.bindUpload(
action: { Issue.record("Retired pane received upload") }, isAvailable: { true })
var requests = 0
let currentBinding = owner.bindUpload(action: { requests += 1 }, isAvailable: { true })
owner.updateUploadAvailability(for: oldBinding, isAvailable: { false })
#expect(!owner.unbindUpload(oldBinding))
let title = String(localized: AppStrings.Terminal.uploadFile)
let item = try #require(view.selectionContextMenu().item(withTitle: title))
#expect(item.isEnabled)
_ = view.perform(item.action, with: item)
#expect(requests == 1)
#expect(owner.unbindUpload(currentBinding))
#expect(view.selectionContextMenu().item(withTitle: title) == nil)
}
@Test func defaultMenuValidatesPasteAndOptionBypassesAutomaticPaste() throws {
let pasteboard = NSPasteboard.general
let saved = (pasteboard.pasteboardItems ?? []).map { item in
Dictionary(
uniqueKeysWithValues: item.types.compactMap { type in
item.data(forType: type).map { (type, $0) }
})
}
defer {
pasteboard.clearContents()
pasteboard.writeObjects(
saved.map { values in
let item = NSPasteboardItem()
for (type, data) in values { item.setData(data, forType: type) }
return item
})
}
let view = TermindTerminalView(frame: .zero)
let event = try #require(
NSEvent.mouseEvent(
with: .rightMouseDown, location: .zero, modifierFlags: [], timestamp: 1,
windowNumber: 0, context: nil, eventNumber: 0, clickCount: 1, pressure: 1))
pasteboard.clearContents()
let emptyMenu = try #require(view.menu(for: event))
let pasteTitle = String(localized: AppStrings.Common.paste)
#expect(emptyMenu.item(withTitle: pasteTitle)?.isEnabled == false)
#expect(emptyMenu.items.contains { $0.action == #selector(view.selectAll(_:)) && $0.isEnabled })
#expect(!emptyMenu.items.contains { $0.action == #selector(view.copy(_:)) })
pasteboard.setString("echo hello", forType: .string)
#expect(view.menu(for: event)?.item(withTitle: pasteTitle)?.isEnabled == true)
view.pasteOnRightClick = true
#expect(view.menu(for: event) == nil)
let optionEvent = try #require(
NSEvent.mouseEvent(
with: .rightMouseDown, location: .zero, modifierFlags: .option, timestamp: 1,
windowNumber: 0, context: nil, eventNumber: 0, clickCount: 1, pressure: 1))
#expect(view.menu(for: optionEvent)?.item(withTitle: pasteTitle)?.isEnabled == true)
}
}