mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-05 07:30:11 +00:00
[refactor] centralize hardcoded URLs into organized constants
- Create src/constants/urls.ts with centralized URL constants (COMFY_URLS, GITHUB_REPOS, MODEL_SOURCES, DEVELOPER_TOOLS) - Move runtime domain config to src/config/comfyDomain.ts to allow forkers to customize via env var - Rename uvMirrors.ts to mirrors.ts for better naming consistency - Add platform and locale-aware desktop guide URL generation (matching PR #4471) - Update 10 components to use centralized URL constants - Add comprehensive unit and e2e tests for URL constants validation This refactoring improves maintainability by centralizing 150+ hardcoded URLs found across 50+ files into a single organized structure.
This commit is contained in:
@@ -38,23 +38,14 @@ import { useI18n } from 'vue-i18n'
|
||||
|
||||
import FileDownload from '@/components/common/FileDownload.vue'
|
||||
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
|
||||
import { MODEL_SOURCES } from '@/constants/urls'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { isElectron } from '@/utils/envUtil'
|
||||
|
||||
// TODO: Read this from server internal API rather than hardcoding here
|
||||
// as some installations may wish to use custom sources
|
||||
const allowedSources = [
|
||||
'https://civitai.com/',
|
||||
'https://huggingface.co/',
|
||||
'http://localhost:' // Included for testing usage only
|
||||
]
|
||||
/** @todo Read this from server internal API rather than hardcoding here */
|
||||
const allowedSources = MODEL_SOURCES.allowedDomains
|
||||
const allowedSuffixes = ['.safetensors', '.sft']
|
||||
// Models that fail above conditions but are still allowed
|
||||
const whiteListedUrls = new Set([
|
||||
'https://huggingface.co/stabilityai/stable-zero123/resolve/main/stable_zero123.ckpt',
|
||||
'https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_depth_sd14v1.pth?download=true',
|
||||
'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth'
|
||||
])
|
||||
const whiteListedUrls = new Set(MODEL_SOURCES.whitelistedUrls)
|
||||
|
||||
interface ModelInfo {
|
||||
name: string
|
||||
|
||||
@@ -123,6 +123,7 @@ import Button from 'primevue/button'
|
||||
import { type CSSProperties, computed, nextTick, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { COMFY_URLS, GITHUB_REPOS, getDesktopGuideUrl } from '@/constants/urls'
|
||||
import { type ReleaseNote } from '@/services/releaseService'
|
||||
import { useCommandStore } from '@/stores/commandStore'
|
||||
import { useReleaseStore } from '@/stores/releaseStore'
|
||||
@@ -143,11 +144,10 @@ interface MenuItem {
|
||||
|
||||
// Constants
|
||||
const EXTERNAL_LINKS = {
|
||||
DOCS: 'https://docs.comfy.org/',
|
||||
DISCORD: 'https://www.comfy.org/discord',
|
||||
GITHUB: 'https://github.com/comfyanonymous/ComfyUI',
|
||||
DESKTOP_GUIDE: 'https://comfyorg.notion.site/',
|
||||
UPDATE_GUIDE: 'https://docs.comfy.org/installation/update_comfyui'
|
||||
DOCS: COMFY_URLS.docs.base,
|
||||
DISCORD: COMFY_URLS.community.discord,
|
||||
GITHUB: GITHUB_REPOS.comfyui,
|
||||
UPDATE_GUIDE: COMFY_URLS.docs.installation.update
|
||||
} as const
|
||||
|
||||
const TIME_UNITS = {
|
||||
@@ -199,7 +199,7 @@ const menuItems = computed<MenuItem[]>(() => {
|
||||
type: 'item',
|
||||
label: t('helpCenter.desktopUserGuide'),
|
||||
action: () => {
|
||||
openExternalLink(EXTERNAL_LINKS.DESKTOP_GUIDE)
|
||||
openExternalLink(getDesktopGuideUrl(locale.value))
|
||||
emit('close')
|
||||
}
|
||||
},
|
||||
@@ -451,8 +451,8 @@ const onUpdate = (_: ReleaseNote): void => {
|
||||
const getChangelogUrl = (): string => {
|
||||
const isChineseLocale = locale.value === 'zh'
|
||||
return isChineseLocale
|
||||
? 'https://docs.comfy.org/zh-CN/changelog'
|
||||
: 'https://docs.comfy.org/changelog'
|
||||
? COMFY_URLS.docs.changelog.zh
|
||||
: COMFY_URLS.docs.changelog.en
|
||||
}
|
||||
|
||||
// Lifecycle
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { COMFY_URLS } from '@/constants/urls'
|
||||
import type { ReleaseNote } from '@/services/releaseService'
|
||||
import { useReleaseStore } from '@/stores/releaseStore'
|
||||
import { formatVersionAnchor } from '@/utils/formatUtil'
|
||||
@@ -72,8 +73,8 @@ const shouldShow = computed(
|
||||
const changelogUrl = computed(() => {
|
||||
const isChineseLocale = locale.value === 'zh'
|
||||
const baseUrl = isChineseLocale
|
||||
? 'https://docs.comfy.org/zh-CN/changelog'
|
||||
: 'https://docs.comfy.org/changelog'
|
||||
? COMFY_URLS.docs.changelog.zh
|
||||
: COMFY_URLS.docs.changelog.en
|
||||
|
||||
if (latestRelease.value?.version) {
|
||||
const versionAnchor = formatVersionAnchor(latestRelease.value.version)
|
||||
@@ -120,7 +121,7 @@ const handleLearnMore = () => {
|
||||
}
|
||||
|
||||
const handleUpdate = () => {
|
||||
window.open('https://docs.comfy.org/installation/update_comfyui', '_blank')
|
||||
window.open(COMFY_URLS.docs.installation.update, '_blank')
|
||||
dismissToast()
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ import { marked } from 'marked'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { COMFY_URLS } from '@/constants/urls'
|
||||
import type { ReleaseNote } from '@/services/releaseService'
|
||||
import { useReleaseStore } from '@/stores/releaseStore'
|
||||
import { formatVersionAnchor } from '@/utils/formatUtil'
|
||||
@@ -92,8 +93,8 @@ const shouldShow = computed(
|
||||
const changelogUrl = computed(() => {
|
||||
const isChineseLocale = locale.value === 'zh'
|
||||
const baseUrl = isChineseLocale
|
||||
? 'https://docs.comfy.org/zh-CN/changelog'
|
||||
: 'https://docs.comfy.org/changelog'
|
||||
? COMFY_URLS.docs.changelog.zh
|
||||
: COMFY_URLS.docs.changelog.en
|
||||
|
||||
if (latestRelease.value?.version) {
|
||||
const versionAnchor = formatVersionAnchor(latestRelease.value.version)
|
||||
|
||||
@@ -43,7 +43,7 @@ import Panel from 'primevue/panel'
|
||||
import { ModelRef, computed, onMounted, ref } from 'vue'
|
||||
|
||||
import MirrorItem from '@/components/install/mirror/MirrorItem.vue'
|
||||
import { PYPI_MIRROR, PYTHON_MIRROR, UVMirror } from '@/constants/uvMirrors'
|
||||
import { PYPI_MIRROR, PYTHON_MIRROR, UVMirror } from '@/constants/mirrors'
|
||||
import { t } from '@/i18n'
|
||||
import { isInChina } from '@/utils/networkUtil'
|
||||
import { ValidationState, mergeValidationStates } from '@/utils/validationUtil'
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import UrlInput from '@/components/common/UrlInput.vue'
|
||||
import { UVMirror } from '@/constants/uvMirrors'
|
||||
import { UVMirror } from '@/constants/mirrors'
|
||||
import { normalizeI18nKey } from '@/utils/formatUtil'
|
||||
import { checkMirrorReachable } from '@/utils/networkUtil'
|
||||
import { ValidationState } from '@/utils/validationUtil'
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
DEFAULT_DARK_COLOR_PALETTE,
|
||||
DEFAULT_LIGHT_COLOR_PALETTE
|
||||
} from '@/constants/coreColorPalettes'
|
||||
import { COMFY_URLS, GITHUB_REPOS } from '@/constants/urls'
|
||||
import { t } from '@/i18n'
|
||||
import { api } from '@/scripts/api'
|
||||
import { app } from '@/scripts/app'
|
||||
@@ -543,10 +544,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
menubarLabel: 'ComfyUI Issues',
|
||||
versionAdded: '1.5.5',
|
||||
function: () => {
|
||||
window.open(
|
||||
'https://github.com/comfyanonymous/ComfyUI/issues',
|
||||
'_blank'
|
||||
)
|
||||
window.open(GITHUB_REPOS.comfyuiIssues, '_blank')
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -556,7 +554,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
menubarLabel: 'ComfyUI Docs',
|
||||
versionAdded: '1.5.5',
|
||||
function: () => {
|
||||
window.open('https://docs.comfy.org/', '_blank')
|
||||
window.open(COMFY_URLS.docs.base, '_blank')
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -566,7 +564,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
menubarLabel: 'Comfy-Org Discord',
|
||||
versionAdded: '1.5.5',
|
||||
function: () => {
|
||||
window.open('https://www.comfy.org/discord', '_blank')
|
||||
window.open(COMFY_URLS.community.discord, '_blank')
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -646,7 +644,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
menubarLabel: 'ComfyUI Forum',
|
||||
versionAdded: '1.8.2',
|
||||
function: () => {
|
||||
window.open('https://forum.comfy.org/', '_blank')
|
||||
window.open(COMFY_URLS.community.forum.base, '_blank')
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
14
src/config/comfyDomain.ts
Normal file
14
src/config/comfyDomain.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Base domain configuration and core website URLs
|
||||
* Forkers can change the base domain to use their own
|
||||
*/
|
||||
export const COMFY_BASE_DOMAIN =
|
||||
process.env.VITE_COMFY_BASE_DOMAIN || 'comfy.org'
|
||||
|
||||
const WEBSITE_BASE_URL = `https://www.${COMFY_BASE_DOMAIN}`
|
||||
|
||||
export const COMFY_WEBSITE_URLS = {
|
||||
base: WEBSITE_BASE_URL,
|
||||
termsOfService: `${WEBSITE_BASE_URL}/terms-of-service`,
|
||||
privacy: `${WEBSITE_BASE_URL}/privacy`
|
||||
}
|
||||
95
src/constants/urls.ts
Normal file
95
src/constants/urls.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* URL constants for ComfyUI frontend
|
||||
* Centralized location for all URL references
|
||||
*/
|
||||
import { COMFY_BASE_DOMAIN } from '@/config/comfyDomain'
|
||||
|
||||
const DOCS_BASE_URL = `https://docs.${COMFY_BASE_DOMAIN}`
|
||||
const FORUM_BASE_URL = `https://forum.${COMFY_BASE_DOMAIN}`
|
||||
const WEBSITE_BASE_URL = `https://www.${COMFY_BASE_DOMAIN}`
|
||||
|
||||
export const COMFY_URLS = {
|
||||
website: {
|
||||
base: WEBSITE_BASE_URL,
|
||||
termsOfService: `${WEBSITE_BASE_URL}/terms-of-service`,
|
||||
privacy: `${WEBSITE_BASE_URL}/privacy`
|
||||
},
|
||||
docs: {
|
||||
base: DOCS_BASE_URL,
|
||||
changelog: {
|
||||
en: `${DOCS_BASE_URL}/changelog`,
|
||||
zh: `${DOCS_BASE_URL}/zh-CN/changelog`
|
||||
},
|
||||
installation: {
|
||||
update: `${DOCS_BASE_URL}/installation/update_comfyui`
|
||||
},
|
||||
tutorials: {
|
||||
apiNodes: {
|
||||
overview: `${DOCS_BASE_URL}/tutorials/api-nodes/overview`,
|
||||
faq: `${DOCS_BASE_URL}/tutorials/api-nodes/faq`,
|
||||
pricing: `${DOCS_BASE_URL}/tutorials/api-nodes/pricing`,
|
||||
apiKeyLogin: `${DOCS_BASE_URL}/interface/user#logging-in-with-an-api-key`,
|
||||
nonWhitelistedLogin: `${DOCS_BASE_URL}/tutorials/api-nodes/overview#log-in-with-api-key-on-non-whitelisted-websites`
|
||||
}
|
||||
},
|
||||
getLocalized: (path: string, locale: string) => {
|
||||
return locale === 'zh' || locale === 'zh-CN'
|
||||
? `${DOCS_BASE_URL}/zh-CN/${path}`
|
||||
: `${DOCS_BASE_URL}/${path}`
|
||||
}
|
||||
},
|
||||
community: {
|
||||
discord: `${WEBSITE_BASE_URL}/discord`,
|
||||
forum: {
|
||||
base: `${FORUM_BASE_URL}/`,
|
||||
v1Feedback: `${FORUM_BASE_URL}/c/v1-feedback/`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const GITHUB_REPOS = {
|
||||
comfyui: 'https://github.com/comfyanonymous/ComfyUI',
|
||||
comfyuiIssues: 'https://github.com/comfyanonymous/ComfyUI/issues',
|
||||
frontend: 'https://github.com/Comfy-Org/ComfyUI_frontend',
|
||||
electron: 'https://github.com/Comfy-Org/electron',
|
||||
desktopPlatforms:
|
||||
'https://github.com/Comfy-Org/desktop#currently-supported-platforms'
|
||||
}
|
||||
|
||||
export const MODEL_SOURCES = {
|
||||
repos: {
|
||||
civitai: 'https://civitai.com/',
|
||||
huggingface: 'https://huggingface.co/'
|
||||
},
|
||||
whitelistedUrls: [
|
||||
'https://huggingface.co/stabilityai/stable-zero123/resolve/main/stable_zero123.ckpt',
|
||||
'https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_depth_sd14v1.pth?download=true',
|
||||
'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth'
|
||||
],
|
||||
allowedDomains: [
|
||||
'https://civitai.com/',
|
||||
'https://huggingface.co/',
|
||||
'http://localhost:' // TODO: Remove in production
|
||||
]
|
||||
}
|
||||
|
||||
export const DEVELOPER_TOOLS = {
|
||||
git: 'https://git-scm.com/downloads/',
|
||||
vcRedist: 'https://aka.ms/vs/17/release/vc_redist.x64.exe',
|
||||
uv: 'https://docs.astral.sh/uv/getting-started/installation/'
|
||||
}
|
||||
|
||||
// Platform and locale-aware desktop guide URL generator
|
||||
export const getDesktopGuideUrl = (locale: string): string => {
|
||||
const isChineseLocale = locale === 'zh'
|
||||
const isMacOS =
|
||||
typeof navigator !== 'undefined' &&
|
||||
navigator.platform.toUpperCase().indexOf('MAC') >= 0
|
||||
|
||||
const platform = isMacOS ? 'macos' : 'windows'
|
||||
const baseUrl = isChineseLocale
|
||||
? `https://docs.${COMFY_BASE_DOMAIN}/zh-CN/installation/desktop`
|
||||
: `https://docs.${COMFY_BASE_DOMAIN}/installation/desktop`
|
||||
|
||||
return `${baseUrl}/${platform}`
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import log from 'loglevel'
|
||||
|
||||
import { PYTHON_MIRROR } from '@/constants/uvMirrors'
|
||||
import { t } from '@/i18n'
|
||||
import { PYTHON_MIRROR } from '@/constants/mirrors'
|
||||
import { getDesktopGuideUrl } from '@/constants/urls'
|
||||
import { i18n, t } from '@/i18n'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useToastStore } from '@/stores/toastStore'
|
||||
@@ -159,7 +160,7 @@ import { checkMirrorReachable } from '@/utils/networkUtil'
|
||||
label: 'Desktop User Guide',
|
||||
icon: 'pi pi-book',
|
||||
function() {
|
||||
window.open('https://comfyorg.notion.site/', '_blank')
|
||||
window.open(getDesktopGuideUrl(i18n.global.locale.value), '_blank')
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { COMFY_URLS, GITHUB_REPOS } from '@/constants/urls'
|
||||
import { AboutPageBadge } from '@/types/comfy'
|
||||
import { electronAPI, isElectron } from '@/utils/envUtil'
|
||||
|
||||
@@ -24,20 +25,20 @@ export const useAboutPanelStore = defineStore('aboutPanel', () => {
|
||||
? 'v' + electronAPI().getComfyUIVersion()
|
||||
: coreVersion.value
|
||||
}`,
|
||||
url: 'https://github.com/comfyanonymous/ComfyUI',
|
||||
url: GITHUB_REPOS.comfyui,
|
||||
icon: 'pi pi-github'
|
||||
},
|
||||
{
|
||||
label: `ComfyUI_frontend v${frontendVersion}`,
|
||||
url: 'https://github.com/Comfy-Org/ComfyUI_frontend',
|
||||
url: GITHUB_REPOS.frontend,
|
||||
icon: 'pi pi-github'
|
||||
},
|
||||
{
|
||||
label: 'Discord',
|
||||
url: 'https://www.comfy.org/discord',
|
||||
url: COMFY_URLS.community.discord,
|
||||
icon: 'pi pi-discord'
|
||||
},
|
||||
{ label: 'ComfyOrg', url: 'https://www.comfy.org/', icon: 'pi pi-globe' }
|
||||
{ label: 'ComfyOrg', url: COMFY_URLS.website.base, icon: 'pi pi-globe' }
|
||||
])
|
||||
|
||||
const allBadges = computed<AboutPageBadge[]>(() => [
|
||||
|
||||
144
tests-ui/tests/constants/urlConstants.test.ts
Normal file
144
tests-ui/tests/constants/urlConstants.test.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { COMFY_BASE_DOMAIN, COMFY_WEBSITE_URLS } from '@/config/comfyDomain'
|
||||
import { PYPI_MIRROR, PYTHON_MIRROR } from '@/constants/mirrors'
|
||||
import {
|
||||
COMFY_URLS,
|
||||
DEVELOPER_TOOLS,
|
||||
GITHUB_REPOS,
|
||||
MODEL_SOURCES,
|
||||
getDesktopGuideUrl
|
||||
} from '@/constants/urls'
|
||||
|
||||
describe('URL Constants', () => {
|
||||
describe('URL Format Validation', () => {
|
||||
it('should have valid HTTPS URLs throughout', () => {
|
||||
const httpsPattern =
|
||||
/^https:\/\/[a-z0-9]+([-.][a-z0-9]+)*\.[a-z]{2,}(:[0-9]{1,5})?(\/.*)?$/i
|
||||
|
||||
// Test COMFY_URLS
|
||||
expect(COMFY_URLS.website.base).toMatch(httpsPattern)
|
||||
expect(COMFY_URLS.docs.base).toMatch(httpsPattern)
|
||||
expect(COMFY_URLS.community.discord).toMatch(httpsPattern)
|
||||
|
||||
// Test GITHUB_REPOS
|
||||
Object.values(GITHUB_REPOS).forEach((url) => {
|
||||
expect(url).toMatch(httpsPattern)
|
||||
})
|
||||
|
||||
// Test MODEL_SOURCES
|
||||
Object.values(MODEL_SOURCES.repos).forEach((url) => {
|
||||
expect(url).toMatch(httpsPattern)
|
||||
})
|
||||
|
||||
// Test DEVELOPER_TOOLS
|
||||
Object.values(DEVELOPER_TOOLS).forEach((url) => {
|
||||
expect(url).toMatch(httpsPattern)
|
||||
})
|
||||
})
|
||||
|
||||
it('should have proper GitHub URL format', () => {
|
||||
const githubPattern = /^https:\/\/github\.com\/[\w-]+\/[\w-]+(\/[\w-]+)?$/
|
||||
|
||||
expect(GITHUB_REPOS.comfyui).toMatch(githubPattern)
|
||||
expect(GITHUB_REPOS.comfyuiIssues).toMatch(githubPattern)
|
||||
expect(GITHUB_REPOS.frontend).toMatch(githubPattern)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Mirror Configuration', () => {
|
||||
it('should have valid mirror URLs', () => {
|
||||
const urlPattern =
|
||||
/^https?:\/\/[a-z0-9]+([-\.]{1}[a-z0-9]+)*\.[a-z]{2,}(:[0-9]{1,5})?(\/.*)?$/i
|
||||
|
||||
expect(PYTHON_MIRROR.mirror).toMatch(urlPattern)
|
||||
expect(PYTHON_MIRROR.fallbackMirror).toMatch(urlPattern)
|
||||
expect(PYPI_MIRROR.mirror).toMatch(urlPattern)
|
||||
expect(PYPI_MIRROR.fallbackMirror).toMatch(urlPattern)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Domain Configuration', () => {
|
||||
it('should have valid domain format', () => {
|
||||
const domainPattern = /^[a-z0-9]+([-.][a-z0-9]+)*\.[a-z]{2,}$/i
|
||||
expect(COMFY_BASE_DOMAIN).toMatch(domainPattern)
|
||||
})
|
||||
|
||||
it('should construct proper website URLs from base domain', () => {
|
||||
const expectedBase = `https://www.${COMFY_BASE_DOMAIN}`
|
||||
expect(COMFY_WEBSITE_URLS.base).toBe(expectedBase)
|
||||
expect(COMFY_WEBSITE_URLS.termsOfService).toBe(
|
||||
`${expectedBase}/terms-of-service`
|
||||
)
|
||||
expect(COMFY_WEBSITE_URLS.privacy).toBe(`${expectedBase}/privacy`)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Localization', () => {
|
||||
it('should handle valid language codes in getLocalized', () => {
|
||||
const validLanguageCodes = ['en', 'zh', 'ja', 'ko', 'es', 'fr', 'de']
|
||||
|
||||
validLanguageCodes.forEach((lang) => {
|
||||
const result = COMFY_URLS.docs.getLocalized('test-path', lang)
|
||||
expect(result).toMatch(/^\/docs\/(([a-z]{2}-[A-Z]{2}\/)?test-path)$/)
|
||||
})
|
||||
})
|
||||
|
||||
it('should properly format localized paths', () => {
|
||||
expect(COMFY_URLS.docs.getLocalized('test-path', 'en')).toBe(
|
||||
'/docs/test-path'
|
||||
)
|
||||
expect(COMFY_URLS.docs.getLocalized('test-path', 'zh')).toBe(
|
||||
'/docs/zh-CN/test-path'
|
||||
)
|
||||
expect(COMFY_URLS.docs.getLocalized('/', 'en')).toBe('/docs/')
|
||||
expect(COMFY_URLS.docs.getLocalized('/', 'zh')).toBe('/docs/zh-CN/')
|
||||
})
|
||||
|
||||
it('should generate platform and locale-aware desktop guide URLs', () => {
|
||||
// Test English locale
|
||||
const enUrl = getDesktopGuideUrl('en')
|
||||
expect(enUrl).toMatch(
|
||||
/^https:\/\/docs\.comfy\.org\/installation\/desktop\/(windows|macos)$/
|
||||
)
|
||||
|
||||
// Test Chinese locale
|
||||
const zhUrl = getDesktopGuideUrl('zh')
|
||||
expect(zhUrl).toMatch(
|
||||
/^https:\/\/docs\.comfy\.org\/zh-CN\/installation\/desktop\/(windows|macos)$/
|
||||
)
|
||||
|
||||
// Test other locales default to English
|
||||
const frUrl = getDesktopGuideUrl('fr')
|
||||
expect(frUrl).toMatch(
|
||||
/^https:\/\/docs\.comfy\.org\/installation\/desktop\/(windows|macos)$/
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Security', () => {
|
||||
it('should only use secure HTTPS for external URLs', () => {
|
||||
const allUrls = [
|
||||
...Object.values(GITHUB_REPOS),
|
||||
...Object.values(MODEL_SOURCES.repos),
|
||||
...Object.values(DEVELOPER_TOOLS),
|
||||
COMFY_URLS.website.base,
|
||||
COMFY_URLS.docs.base,
|
||||
COMFY_URLS.community.discord
|
||||
]
|
||||
|
||||
allUrls.forEach((url) => {
|
||||
expect(url.startsWith('https://')).toBe(true)
|
||||
expect(url.startsWith('http://')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
it('should have valid domain allowlist for model sources', () => {
|
||||
const domainPattern = /^[a-z0-9]+([-.][a-z0-9]+)*\.[a-z]{2,}$/i
|
||||
|
||||
MODEL_SOURCES.allowedDomains.forEach((domain) => {
|
||||
expect(domain).toMatch(domainPattern)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user