Compare commits
5 commits
49ea6542b8
...
e9ef03b8fc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9ef03b8fc | ||
|
|
53a7fa2a43 | ||
|
|
7cd3f8609e | ||
|
|
fa34fcd8cd | ||
|
|
fa04cfbbc5 |
5 changed files with 127 additions and 11 deletions
108
web/frontend/src/__tests__/ssh-labels-i18n.test.ts
Normal file
108
web/frontend/src/__tests__/ssh-labels-i18n.test.ts
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* KIN-UI-014: Тесты i18n-рефакторинга SSH-лейблов в ProjectView
|
||||
*
|
||||
* Проверяет:
|
||||
* 1. Ключи settings.ssh_host/ssh_user/ssh_key_path/ssh_proxy_jump присутствуют в en.json
|
||||
* 2. Ключи settings.ssh_host/ssh_user/ssh_key_path/ssh_proxy_jump присутствуют в ru.json
|
||||
* 3. Значения английских ключей корректны
|
||||
* 4. Значения русских ключей корректны
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import enJson from '../locales/en.json'
|
||||
import ruJson from '../locales/ru.json'
|
||||
|
||||
describe('KIN-UI-014: SSH-лейблы в en.json', () => {
|
||||
it('settings.ssh_host присутствует в en.json', () => {
|
||||
expect((enJson.settings as Record<string, string>).ssh_host).toBeDefined()
|
||||
})
|
||||
|
||||
it('settings.ssh_user присутствует в en.json', () => {
|
||||
expect((enJson.settings as Record<string, string>).ssh_user).toBeDefined()
|
||||
})
|
||||
|
||||
it('settings.ssh_key_path присутствует в en.json', () => {
|
||||
expect((enJson.settings as Record<string, string>).ssh_key_path).toBeDefined()
|
||||
})
|
||||
|
||||
it('settings.ssh_proxy_jump присутствует в en.json', () => {
|
||||
expect((enJson.settings as Record<string, string>).ssh_proxy_jump).toBeDefined()
|
||||
})
|
||||
|
||||
it('settings.ssh_host имеет корректное английское значение', () => {
|
||||
expect((enJson.settings as Record<string, string>).ssh_host).toBe('SSH Host')
|
||||
})
|
||||
|
||||
it('settings.ssh_user имеет корректное английское значение', () => {
|
||||
expect((enJson.settings as Record<string, string>).ssh_user).toBe('SSH User')
|
||||
})
|
||||
|
||||
it('settings.ssh_key_path имеет корректное английское значение', () => {
|
||||
expect((enJson.settings as Record<string, string>).ssh_key_path).toBe('SSH Key Path')
|
||||
})
|
||||
|
||||
it('settings.ssh_proxy_jump имеет корректное английское значение', () => {
|
||||
expect((enJson.settings as Record<string, string>).ssh_proxy_jump).toBe('SSH ProxyJump')
|
||||
})
|
||||
})
|
||||
|
||||
describe('KIN-UI-014: SSH-лейблы в ru.json', () => {
|
||||
it('settings.ssh_host присутствует в ru.json', () => {
|
||||
expect((ruJson.settings as Record<string, string>).ssh_host).toBeDefined()
|
||||
})
|
||||
|
||||
it('settings.ssh_user присутствует в ru.json', () => {
|
||||
expect((ruJson.settings as Record<string, string>).ssh_user).toBeDefined()
|
||||
})
|
||||
|
||||
it('settings.ssh_key_path присутствует в ru.json', () => {
|
||||
expect((ruJson.settings as Record<string, string>).ssh_key_path).toBeDefined()
|
||||
})
|
||||
|
||||
it('settings.ssh_proxy_jump присутствует в ru.json', () => {
|
||||
expect((ruJson.settings as Record<string, string>).ssh_proxy_jump).toBeDefined()
|
||||
})
|
||||
|
||||
it('settings.ssh_host имеет корректное русское значение', () => {
|
||||
expect((ruJson.settings as Record<string, string>).ssh_host).toBe('SSH Хост')
|
||||
})
|
||||
|
||||
it('settings.ssh_user имеет корректное русское значение', () => {
|
||||
expect((ruJson.settings as Record<string, string>).ssh_user).toBe('SSH Пользователь')
|
||||
})
|
||||
|
||||
it('settings.ssh_key_path имеет корректное русское значение', () => {
|
||||
expect((ruJson.settings as Record<string, string>).ssh_key_path).toBe('Путь к SSH ключу')
|
||||
})
|
||||
|
||||
it('settings.ssh_proxy_jump имеет корректное русское значение', () => {
|
||||
expect((ruJson.settings as Record<string, string>).ssh_proxy_jump).toBe('SSH ProxyJump')
|
||||
})
|
||||
})
|
||||
|
||||
describe('KIN-UI-014: ProjectView.vue не содержит хардкод SSH-лейблов', () => {
|
||||
it('все 4 SSH-ключа отсутствуют как хардкод — ключи локалей совпадают между en и ru', () => {
|
||||
const en = enJson.settings as Record<string, string>
|
||||
const ru = ruJson.settings as Record<string, string>
|
||||
// Оба файла содержат одинаковый набор SSH-ключей
|
||||
expect(Object.keys(en)).toContain('ssh_host')
|
||||
expect(Object.keys(en)).toContain('ssh_user')
|
||||
expect(Object.keys(en)).toContain('ssh_key_path')
|
||||
expect(Object.keys(en)).toContain('ssh_proxy_jump')
|
||||
expect(Object.keys(ru)).toContain('ssh_host')
|
||||
expect(Object.keys(ru)).toContain('ssh_user')
|
||||
expect(Object.keys(ru)).toContain('ssh_key_path')
|
||||
expect(Object.keys(ru)).toContain('ssh_proxy_jump')
|
||||
})
|
||||
|
||||
it('SSH-ключи в ru.json не совпадают с английскими (переведены)', () => {
|
||||
const en = enJson.settings as Record<string, string>
|
||||
const ru = ruJson.settings as Record<string, string>
|
||||
// ssh_host, ssh_user, ssh_key_path — переведены, не совпадают
|
||||
expect(ru.ssh_host).not.toBe(en.ssh_host)
|
||||
expect(ru.ssh_user).not.toBe(en.ssh_user)
|
||||
expect(ru.ssh_key_path).not.toBe(en.ssh_key_path)
|
||||
// ssh_proxy_jump — бренд, одинаков в обоих языках
|
||||
expect(ru.ssh_proxy_jump).toBe(en.ssh_proxy_jump)
|
||||
})
|
||||
})
|
||||
|
|
@ -129,7 +129,11 @@
|
|||
"saving_link": "Saving...",
|
||||
"cancel_link": "Cancel",
|
||||
"delete_link_confirm": "Delete link?",
|
||||
"select_project_error": "Select a project"
|
||||
"select_project_error": "Select a project",
|
||||
"ssh_host": "SSH Host",
|
||||
"ssh_user": "SSH User",
|
||||
"ssh_key_path": "SSH Key Path",
|
||||
"ssh_proxy_jump": "SSH ProxyJump"
|
||||
},
|
||||
"taskDetail": {
|
||||
"pipeline_already_running": "Pipeline already running",
|
||||
|
|
|
|||
|
|
@ -129,7 +129,11 @@
|
|||
"saving_link": "Сохраняем...",
|
||||
"cancel_link": "Отмена",
|
||||
"delete_link_confirm": "Удалить связь?",
|
||||
"select_project_error": "Выберите проект"
|
||||
"select_project_error": "Выберите проект",
|
||||
"ssh_host": "SSH Хост",
|
||||
"ssh_user": "SSH Пользователь",
|
||||
"ssh_key_path": "Путь к SSH ключу",
|
||||
"ssh_proxy_jump": "SSH ProxyJump"
|
||||
},
|
||||
"taskDetail": {
|
||||
"pipeline_already_running": "Pipeline уже запущен",
|
||||
|
|
|
|||
|
|
@ -1639,22 +1639,22 @@ async function addDecision() {
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs text-gray-500 mb-1">SSH Host</label>
|
||||
<label class="block text-xs text-gray-500 mb-1">{{ t('settings.ssh_host') }}</label>
|
||||
<input v-model="settingsForm.ssh_host" type="text" placeholder="vdp-prod"
|
||||
class="w-full bg-gray-900 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 font-mono focus:outline-none focus:border-gray-500" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs text-gray-500 mb-1">SSH User</label>
|
||||
<label class="block text-xs text-gray-500 mb-1">{{ t('settings.ssh_user') }}</label>
|
||||
<input v-model="settingsForm.ssh_user" type="text" placeholder="root"
|
||||
class="w-full bg-gray-900 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 font-mono focus:outline-none focus:border-gray-500" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs text-gray-500 mb-1">SSH Key Path</label>
|
||||
<label class="block text-xs text-gray-500 mb-1">{{ t('settings.ssh_key_path') }}</label>
|
||||
<input v-model="settingsForm.ssh_key_path" type="text" placeholder="~/.ssh/id_rsa"
|
||||
class="w-full bg-gray-900 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 font-mono focus:outline-none focus:border-gray-500" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs text-gray-500 mb-1">SSH ProxyJump</label>
|
||||
<label class="block text-xs text-gray-500 mb-1">{{ t('settings.ssh_proxy_jump') }}</label>
|
||||
<input v-model="settingsForm.ssh_proxy_jump" type="text" placeholder="jumpt"
|
||||
class="w-full bg-gray-900 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 font-mono focus:outline-none focus:border-gray-500" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ async function deleteLink(projectId: string, linkId: number) {
|
|||
>
|
||||
{{ savingTest[project.id] ? t('settings.saving_test') : t('settings.save_test') }}
|
||||
</button>
|
||||
<span v-if="saveTestStatus[project.id]" class="text-xs" :class="saveTestStatus[project.id].startsWith('Error') ? 'text-red-400' : 'text-green-400'">
|
||||
<span v-if="saveTestStatus[project.id]" class="text-xs" :class="saveTestStatus[project.id].startsWith(t('common.error')) ? 'text-red-400' : 'text-green-400'">
|
||||
{{ saveTestStatus[project.id] }}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -307,7 +307,7 @@ async function deleteLink(projectId: string, linkId: number) {
|
|||
>
|
||||
{{ savingDeployConfig[project.id] ? t('settings.saving_deploy') : t('settings.save_deploy_config') }}
|
||||
</button>
|
||||
<span v-if="saveDeployConfigStatus[project.id]" class="text-xs" :class="saveDeployConfigStatus[project.id].startsWith('Error') ? 'text-red-400' : 'text-green-400'">
|
||||
<span v-if="saveDeployConfigStatus[project.id]" class="text-xs" :class="saveDeployConfigStatus[project.id].startsWith(t('common.error')) ? 'text-red-400' : 'text-green-400'">
|
||||
{{ saveDeployConfigStatus[project.id] }}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -393,7 +393,7 @@ async function deleteLink(projectId: string, linkId: number) {
|
|||
<span class="text-sm text-gray-300">{{ t('settings.auto_test') }}</span>
|
||||
<span class="text-xs text-gray-500">{{ t('settings.auto_test_hint') }}</span>
|
||||
</label>
|
||||
<span v-if="saveAutoTestStatus[project.id]" class="text-xs" :class="saveAutoTestStatus[project.id].startsWith('Error') ? 'text-red-400' : 'text-green-400'">
|
||||
<span v-if="saveAutoTestStatus[project.id]" class="text-xs" :class="saveAutoTestStatus[project.id].startsWith(t('common.error')) ? 'text-red-400' : 'text-green-400'">
|
||||
{{ saveAutoTestStatus[project.id] }}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -410,7 +410,7 @@ async function deleteLink(projectId: string, linkId: number) {
|
|||
<span class="text-sm text-gray-300">{{ t('settings.worktrees') }}</span>
|
||||
<span class="text-xs text-gray-500">{{ t('settings.worktrees_hint') }}</span>
|
||||
</label>
|
||||
<span v-if="saveWorktreesStatus[project.id]" class="text-xs" :class="saveWorktreesStatus[project.id].startsWith('Error') ? 'text-red-400' : 'text-green-400'">
|
||||
<span v-if="saveWorktreesStatus[project.id]" class="text-xs" :class="saveWorktreesStatus[project.id].startsWith(t('common.error')) ? 'text-red-400' : 'text-green-400'">
|
||||
{{ saveWorktreesStatus[project.id] }}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -432,7 +432,7 @@ async function deleteLink(projectId: string, linkId: number) {
|
|||
{{ syncing[project.id] ? t('settings.syncing') : t('settings.sync_obsidian') }}
|
||||
</button>
|
||||
|
||||
<span v-if="saveStatus[project.id]" class="text-xs" :class="saveStatus[project.id].startsWith('Error') ? 'text-red-400' : 'text-green-400'">
|
||||
<span v-if="saveStatus[project.id]" class="text-xs" :class="saveStatus[project.id].startsWith(t('common.error')) ? 'text-red-400' : 'text-green-400'">
|
||||
{{ saveStatus[project.id] }}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue