mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-01 13:59:54 +00:00
## Summary See https://typescript-eslint.io/blog/project-service/ for context. Creates a browser_tests specific tsconfig so that they can be linted. Does not add a package.json script to do the linting yet, but `pnpm exec eslint browser_tests` should work for now. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5633-lint-add-tsconfig-for-browser_tests-fix-existing-violations-2726d73d3650819d8ef2c4b0abc31e14) by [Unito](https://www.unito.io)
220 lines
5.9 KiB
TypeScript
220 lines
5.9 KiB
TypeScript
import { createTestingPinia } from '@pinia/testing'
|
|
import type { VueWrapper } from '@vue/test-utils'
|
|
import { mount } from '@vue/test-utils'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { nextTick } from 'vue'
|
|
import { createI18n } from 'vue-i18n'
|
|
|
|
import BaseTerminal from '@/components/bottomPanel/tabs/terminal/BaseTerminal.vue'
|
|
|
|
// Mock xterm and related modules
|
|
vi.mock('@xterm/xterm', () => ({
|
|
Terminal: vi.fn().mockImplementation(() => ({
|
|
open: vi.fn(),
|
|
dispose: vi.fn(),
|
|
onSelectionChange: vi.fn(() => {
|
|
// Return a disposable
|
|
return {
|
|
dispose: vi.fn()
|
|
}
|
|
}),
|
|
hasSelection: vi.fn(() => false),
|
|
getSelection: vi.fn(() => ''),
|
|
selectAll: vi.fn(),
|
|
clearSelection: vi.fn(),
|
|
loadAddon: vi.fn()
|
|
})),
|
|
IDisposable: vi.fn()
|
|
}))
|
|
|
|
vi.mock('@xterm/addon-fit', () => ({
|
|
FitAddon: vi.fn().mockImplementation(() => ({
|
|
fit: vi.fn(),
|
|
proposeDimensions: vi.fn(() => ({ rows: 24, cols: 80 }))
|
|
}))
|
|
}))
|
|
|
|
const mockTerminal = {
|
|
open: vi.fn(),
|
|
dispose: vi.fn(),
|
|
onSelectionChange: vi.fn(() => ({
|
|
dispose: vi.fn()
|
|
})),
|
|
hasSelection: vi.fn(() => false),
|
|
getSelection: vi.fn(() => ''),
|
|
selectAll: vi.fn(),
|
|
clearSelection: vi.fn()
|
|
}
|
|
|
|
vi.mock('@/composables/bottomPanelTabs/useTerminal', () => ({
|
|
useTerminal: vi.fn(() => ({
|
|
terminal: mockTerminal,
|
|
useAutoSize: vi.fn(() => ({ resize: vi.fn() }))
|
|
}))
|
|
}))
|
|
|
|
vi.mock('@/utils/envUtil', () => ({
|
|
isElectron: vi.fn(() => false),
|
|
electronAPI: vi.fn(() => null)
|
|
}))
|
|
|
|
// Mock clipboard API
|
|
Object.defineProperty(navigator, 'clipboard', {
|
|
value: {
|
|
writeText: vi.fn().mockResolvedValue(undefined)
|
|
},
|
|
configurable: true
|
|
})
|
|
|
|
const i18n = createI18n({
|
|
legacy: false,
|
|
locale: 'en',
|
|
messages: {
|
|
en: {
|
|
serverStart: {
|
|
copySelectionTooltip: 'Copy selection',
|
|
copyAllTooltip: 'Copy all'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
const mountBaseTerminal = () => {
|
|
return mount(BaseTerminal, {
|
|
global: {
|
|
plugins: [
|
|
createTestingPinia({
|
|
createSpy: vi.fn
|
|
}),
|
|
i18n
|
|
],
|
|
stubs: {
|
|
Button: {
|
|
template: '<button v-bind="$attrs"><slot /></button>',
|
|
props: ['icon', 'severity', 'size']
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
describe('BaseTerminal', () => {
|
|
let wrapper: VueWrapper<InstanceType<typeof BaseTerminal>> | undefined
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
afterEach(() => {
|
|
wrapper?.unmount()
|
|
})
|
|
|
|
it('emits created event on mount', () => {
|
|
wrapper = mountBaseTerminal()
|
|
|
|
expect(wrapper.emitted('created')).toBeTruthy()
|
|
expect(wrapper.emitted('created')![0]).toHaveLength(2)
|
|
})
|
|
|
|
it('emits unmounted event on unmount', () => {
|
|
wrapper = mountBaseTerminal()
|
|
wrapper.unmount()
|
|
|
|
expect(wrapper.emitted('unmounted')).toBeTruthy()
|
|
})
|
|
|
|
it('button exists and has correct initial state', async () => {
|
|
wrapper = mountBaseTerminal()
|
|
|
|
const button = wrapper.find('button[aria-label]')
|
|
expect(button.exists()).toBe(true)
|
|
|
|
expect(button.classes()).toContain('opacity-0')
|
|
expect(button.classes()).toContain('pointer-events-none')
|
|
})
|
|
|
|
it('shows correct tooltip when no selection', async () => {
|
|
mockTerminal.hasSelection.mockReturnValue(false)
|
|
wrapper = mountBaseTerminal()
|
|
|
|
await wrapper.trigger('mouseenter')
|
|
await nextTick()
|
|
|
|
const button = wrapper.find('button[aria-label]')
|
|
expect(button.attributes('aria-label')).toBe('Copy all')
|
|
})
|
|
|
|
it('shows correct tooltip when selection exists', async () => {
|
|
mockTerminal.hasSelection.mockReturnValue(true)
|
|
wrapper = mountBaseTerminal()
|
|
|
|
// Trigger the selection change callback that was registered during mount
|
|
expect(mockTerminal.onSelectionChange).toHaveBeenCalled()
|
|
// Access the mock calls - TypeScript can't infer the mock structure dynamically
|
|
const selectionCallback = (mockTerminal.onSelectionChange as any).mock
|
|
.calls[0][0]
|
|
selectionCallback()
|
|
await nextTick()
|
|
|
|
await wrapper.trigger('mouseenter')
|
|
await nextTick()
|
|
|
|
const button = wrapper.find('button[aria-label]')
|
|
expect(button.attributes('aria-label')).toBe('Copy selection')
|
|
})
|
|
|
|
it('copies selected text when selection exists', async () => {
|
|
const selectedText = 'selected text'
|
|
mockTerminal.hasSelection.mockReturnValue(true)
|
|
mockTerminal.getSelection.mockReturnValue(selectedText)
|
|
|
|
wrapper = mountBaseTerminal()
|
|
|
|
await wrapper.trigger('mouseenter')
|
|
await nextTick()
|
|
|
|
const button = wrapper.find('button[aria-label]')
|
|
await button.trigger('click')
|
|
|
|
expect(mockTerminal.selectAll).not.toHaveBeenCalled()
|
|
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(selectedText)
|
|
expect(mockTerminal.clearSelection).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('copies all text when no selection exists', async () => {
|
|
const allText = 'all terminal content'
|
|
mockTerminal.hasSelection.mockReturnValue(false)
|
|
mockTerminal.getSelection
|
|
.mockReturnValueOnce('') // First call returns empty (no selection)
|
|
.mockReturnValueOnce(allText) // Second call after selectAll returns all text
|
|
|
|
wrapper = mountBaseTerminal()
|
|
|
|
await wrapper.trigger('mouseenter')
|
|
await nextTick()
|
|
|
|
const button = wrapper.find('button[aria-label]')
|
|
await button.trigger('click')
|
|
|
|
expect(mockTerminal.selectAll).toHaveBeenCalled()
|
|
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(allText)
|
|
expect(mockTerminal.clearSelection).toHaveBeenCalled()
|
|
})
|
|
|
|
it('does not copy when no text available', async () => {
|
|
mockTerminal.hasSelection.mockReturnValue(false)
|
|
mockTerminal.getSelection.mockReturnValue('')
|
|
|
|
wrapper = mountBaseTerminal()
|
|
|
|
await wrapper.trigger('mouseenter')
|
|
await nextTick()
|
|
|
|
const button = wrapper.find('button[aria-label]')
|
|
await button.trigger('click')
|
|
|
|
expect(mockTerminal.selectAll).toHaveBeenCalled()
|
|
expect(navigator.clipboard.writeText).not.toHaveBeenCalled()
|
|
})
|
|
})
|