Compare commits

...

4 Commits

Author SHA1 Message Date
bymyself
c2280af266 test: add unit tests for DeviceInfo 2026-06-25 13:10:47 -07:00
bymyself
0851ba2f47 test: add unit tests for SystemStatsPanel i18n headers 2026-06-19 14:42:48 -07:00
GitHub Action
356968a11a [automated] Apply ESLint and Oxfmt fixes 2026-05-14 03:29:48 +00:00
bymyself
505d6eca1c refactor: localize system stats headers and fix PyTorch casing
- Add 11 i18n keys for system stats column headers (g.systemStats*)
- Update SystemStatsPanel.vue to use headerKey with $t()
- Fix 'Pytorch' → 'PyTorch' casing in column header

Closes #11870

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-13 20:26:24 -07:00
4 changed files with 176 additions and 15 deletions

View File

@@ -0,0 +1,48 @@
import { render, screen } from '@testing-library/vue'
import { describe, expect, it } from 'vitest'
import type { DeviceStats } from '@/schemas/apiSchema'
import DeviceInfo from './DeviceInfo.vue'
function createDevice(overrides: Partial<DeviceStats> = {}): DeviceStats {
return {
name: 'cuda:0 NVIDIA RTX',
type: 'cuda',
index: 0,
vram_total: 1024,
vram_free: 512,
torch_vram_total: 2048,
torch_vram_free: 256,
...overrides
}
}
function renderDeviceInfo(device: DeviceStats) {
return render(DeviceInfo, { props: { device } })
}
describe('DeviceInfo', () => {
it('renders device name and type as-is', () => {
renderDeviceInfo(createDevice())
expect(screen.getByText('cuda:0 NVIDIA RTX')).toBeTruthy()
expect(screen.getByText('cuda')).toBeTruthy()
})
it('formats vram fields as human-readable sizes', () => {
renderDeviceInfo(
createDevice({
vram_total: 1024,
vram_free: 0,
torch_vram_total: 1048576,
torch_vram_free: 1073741824
})
)
expect(screen.getByText('1 KB')).toBeTruthy()
expect(screen.getByText('0 B')).toBeTruthy()
expect(screen.getByText('1 MB')).toBeTruthy()
expect(screen.getByText('1 GB')).toBeTruthy()
})
})

View File

@@ -0,0 +1,86 @@
import { render, screen } from '@testing-library/vue'
import userEvent from '@testing-library/user-event'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createI18n } from 'vue-i18n'
import enMessages from '@/locales/en/main.json'
import type { SystemStats } from '@/schemas/apiSchema'
import SystemStatsPanel from './SystemStatsPanel.vue'
const copyToClipboard = vi.fn()
vi.mock('@/composables/useCopyToClipboard', () => ({
useCopyToClipboard: () => ({ copyToClipboard })
}))
const i18n = createI18n({
legacy: false,
locale: 'en',
messages: { en: enMessages }
})
function createStats(
overrides: Partial<SystemStats['system']> = {}
): SystemStats {
return {
system: {
os: 'posix',
python_version: '3.12.4',
embedded_python: false,
comfyui_version: 'v1.2.3',
pytorch_version: '2.4.0',
argv: ['main.py', '--listen'],
ram_total: 1024,
ram_free: 512,
installed_templates_version: '1.0.0',
required_templates_version: '1.0.0',
...overrides
},
devices: []
}
}
function renderPanel(stats: SystemStats) {
return render(SystemStatsPanel, {
props: { stats },
global: {
plugins: [i18n],
stubs: { Divider: true, TabView: true, TabPanel: true, DeviceInfo: true }
}
})
}
describe('SystemStatsPanel', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('renders localized headers with corrected PyTorch casing', () => {
renderPanel(createStats())
expect(screen.getByText('PyTorch Version')).toBeTruthy()
expect(screen.queryByText('Pytorch Version')).toBeNull()
expect(screen.getByText('OS')).toBeTruthy()
expect(screen.getByText('Python Version')).toBeTruthy()
expect(screen.getByText('Arguments')).toBeTruthy()
})
it('formats values for display', () => {
renderPanel(createStats({ ram_total: 1024, argv: ['main.py', '--cpu'] }))
expect(screen.getByText('1 KB')).toBeTruthy()
expect(screen.getByText('main.py --cpu')).toBeTruthy()
})
it('copies localized, formatted system info to the clipboard', async () => {
renderPanel(createStats())
await userEvent.click(screen.getByText(enMessages.g.copySystemInfo))
expect(copyToClipboard).toHaveBeenCalledTimes(1)
const copied = copyToClipboard.mock.calls[0][0] as string
expect(copied).toContain('## System Info')
expect(copied).toContain('PyTorch Version: 2.4.0')
expect(copied).toContain('RAM Total: 1 KB')
})
})

View File

@@ -13,7 +13,7 @@
<div class="grid grid-cols-2 gap-2">
<template v-for="col in systemColumns" :key="col.field">
<div :class="cn('font-medium', isOutdated(col) && 'text-danger-100')">
{{ col.header }}
{{ $t(col.headerKey) }}
</div>
<div :class="cn(isOutdated(col) && 'text-danger-100')">
{{ getDisplayValue(col) }}
@@ -58,8 +58,10 @@ import { isCloud } from '@/platform/distribution/types'
import type { SystemStats } from '@/schemas/apiSchema'
import { formatCommitHash, formatSize } from '@/utils/formatUtil'
import { cn } from '@comfyorg/tailwind-utils'
import { useI18n } from 'vue-i18n'
const frontendCommit = __COMFYUI_FRONTEND_COMMIT__
const { t } = useI18n()
const props = defineProps<{
stats: SystemStats
@@ -78,7 +80,7 @@ type SystemInfoKey = keyof SystemStats['system']
type ColumnDef = {
field: SystemInfoKey
header: string
headerKey: string
getValue?: () => string
format?: (value: string) => string
formatNumber?: (value: number) => string
@@ -86,31 +88,45 @@ type ColumnDef = {
/** Columns for local distribution */
const localColumns: ColumnDef[] = [
{ field: 'os', header: 'OS' },
{ field: 'python_version', header: 'Python Version' },
{ field: 'embedded_python', header: 'Embedded Python' },
{ field: 'pytorch_version', header: 'Pytorch Version' },
{ field: 'argv', header: 'Arguments' },
{ field: 'ram_total', header: 'RAM Total', formatNumber: formatSize },
{ field: 'ram_free', header: 'RAM Free', formatNumber: formatSize },
{ field: 'installed_templates_version', header: 'Templates Version' }
{ field: 'os', headerKey: 'g.systemStatsOS' },
{ field: 'python_version', headerKey: 'g.systemStatsPythonVersion' },
{ field: 'embedded_python', headerKey: 'g.systemStatsEmbeddedPython' },
{ field: 'pytorch_version', headerKey: 'g.systemStatsPyTorchVersion' },
{ field: 'argv', headerKey: 'g.systemStatsArguments' },
{
field: 'ram_total',
headerKey: 'g.systemStatsRAMTotal',
formatNumber: formatSize
},
{
field: 'ram_free',
headerKey: 'g.systemStatsRAMFree',
formatNumber: formatSize
},
{
field: 'installed_templates_version',
headerKey: 'g.systemStatsTemplatesVersion'
}
]
/** Columns for cloud distribution */
const cloudColumns: ColumnDef[] = [
{ field: 'cloud_version', header: 'Cloud Version' },
{ field: 'cloud_version', headerKey: 'g.systemStatsCloudVersion' },
{
field: 'comfyui_version',
header: 'ComfyUI Version',
headerKey: 'g.systemStatsComfyUIVersion',
format: formatCommitHash
},
{
field: 'comfyui_frontend_version',
header: 'Frontend Version',
headerKey: 'g.systemStatsFrontendVersion',
getValue: () => frontendCommit,
format: formatCommitHash
},
{ field: 'workflow_templates_version', header: 'Templates Version' }
{
field: 'workflow_templates_version',
headerKey: 'g.systemStatsTemplatesVersion'
}
]
const systemColumns = computed(() => (isCloud ? cloudColumns : localColumns))
@@ -141,7 +157,7 @@ function formatSystemInfoText(): string {
for (const col of systemColumns.value) {
const display = getDisplayValue(col)
if (display !== undefined && display !== '') {
lines.push(`${col.header}: ${display}`)
lines.push(`${t(col.headerKey)}: ${display}`)
}
}

View File

@@ -64,6 +64,17 @@
"insert": "Insert",
"systemInfo": "System Info",
"devices": "Devices",
"systemStatsOS": "OS",
"systemStatsPythonVersion": "Python Version",
"systemStatsEmbeddedPython": "Embedded Python",
"systemStatsPyTorchVersion": "PyTorch Version",
"systemStatsArguments": "Arguments",
"systemStatsRAMTotal": "RAM Total",
"systemStatsRAMFree": "RAM Free",
"systemStatsTemplatesVersion": "Templates Version",
"systemStatsCloudVersion": "Cloud Version",
"systemStatsComfyUIVersion": "ComfyUI Version",
"systemStatsFrontendVersion": "Frontend Version",
"about": "About",
"add": "Add",
"confirm": "Confirm",