mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 07:00:23 +00:00
Update the desktop guide links to make them platform and locale-aware Edited by Terry: Refactor external link management by introducing a centralized useExternalLink composable with automatic locale and platform detection for documentation URLs. - Created useExternalLink composable - A new centralized utility for managing all external links - Dynamic docs URL builder (buildDocsUrl) - Automatically constructs docs.comfy.org URLs with: - Locale detection (Chinese vs English) - Platform detection (macOS vs Windows for desktop) - Flexible path construction with options ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-4471-Add-platform-and-locale-aware-desktop-guide-URL-2346d73d3650815ea4a4dd64be575bbe) by [Unito](https://www.unito.io) --------- Co-authored-by: Terry Jia <terryjia88@gmail.com>
441 lines
13 KiB
TypeScript
441 lines
13 KiB
TypeScript
import { mount } from '@vue/test-utils'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { nextTick } from 'vue'
|
|
|
|
import WhatsNewPopup from '@/platform/updates/components/WhatsNewPopup.vue'
|
|
import type { components } from '@/types/comfyRegistryTypes'
|
|
|
|
type ReleaseNote = components['schemas']['ReleaseNote']
|
|
|
|
// Mock dependencies
|
|
vi.mock('vue-i18n', () => ({
|
|
useI18n: vi.fn(() => ({
|
|
locale: { value: 'en' },
|
|
t: vi.fn((key) => key)
|
|
})),
|
|
createI18n: vi.fn(() => ({
|
|
global: {
|
|
locale: { value: 'en' }
|
|
}
|
|
}))
|
|
}))
|
|
|
|
vi.mock('@/utils/markdownRendererUtil', () => ({
|
|
renderMarkdownToHtml: vi.fn((content) => `<p>${content}</p>`)
|
|
}))
|
|
|
|
vi.mock('@/platform/updates/common/releaseStore', () => ({
|
|
useReleaseStore: vi.fn()
|
|
}))
|
|
|
|
describe('WhatsNewPopup', () => {
|
|
const mockReleaseStore = {
|
|
recentRelease: null as ReleaseNote | null,
|
|
shouldShowPopup: false,
|
|
handleWhatsNewSeen: vi.fn(),
|
|
releases: [] as ReleaseNote[],
|
|
fetchReleases: vi.fn()
|
|
}
|
|
|
|
const createWrapper = (props = {}) => {
|
|
return mount(WhatsNewPopup, {
|
|
props,
|
|
global: {
|
|
mocks: {
|
|
$t: vi.fn((key: string) => {
|
|
const translations: Record<string, string> = {
|
|
'g.close': 'Close',
|
|
'whatsNewPopup.noReleaseNotes': 'No release notes available'
|
|
}
|
|
return translations[key] || key
|
|
})
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
beforeEach(async () => {
|
|
vi.clearAllMocks()
|
|
|
|
// Reset mock store
|
|
mockReleaseStore.recentRelease = null
|
|
mockReleaseStore.shouldShowPopup = false
|
|
mockReleaseStore.releases = []
|
|
|
|
// Mock release store
|
|
const { useReleaseStore } = await import(
|
|
'@/platform/updates/common/releaseStore'
|
|
)
|
|
vi.mocked(useReleaseStore).mockReturnValue(mockReleaseStore as any)
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
describe('visibility', () => {
|
|
it('should not show when shouldShowPopup is false', () => {
|
|
mockReleaseStore.shouldShowPopup = false
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
expect(wrapper.find('.whats-new-popup-container').exists()).toBe(false)
|
|
})
|
|
|
|
it('should show when shouldShowPopup is true and not dismissed', () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: 'New features added',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
expect(wrapper.find('.whats-new-popup-container').exists()).toBe(true)
|
|
expect(wrapper.find('.whats-new-popup').exists()).toBe(true)
|
|
})
|
|
|
|
it('should hide when dismissed locally', async () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: 'New features added',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
// Initially visible
|
|
expect(wrapper.find('.whats-new-popup-container').exists()).toBe(true)
|
|
|
|
// Click close button
|
|
await wrapper.find('.close-button').trigger('click')
|
|
|
|
// Should be hidden
|
|
expect(wrapper.find('.whats-new-popup-container').exists()).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('content rendering', () => {
|
|
it('should render release content using renderMarkdownToHtml', async () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: '# Release Notes\n\nNew features',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
// Check that the content is rendered (renderMarkdownToHtml is mocked to return processed content)
|
|
expect(wrapper.find('.content-text').exists()).toBe(true)
|
|
const contentHtml = wrapper.find('.content-text').html()
|
|
expect(contentHtml).toContain('<p># Release Notes')
|
|
})
|
|
|
|
it('should handle missing release content', () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: '',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
expect(wrapper.find('.content-text').html()).toContain(
|
|
'whatsNewPopup.noReleaseNotes'
|
|
)
|
|
})
|
|
|
|
it('should handle markdown parsing errors gracefully', () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: 'Content with\nnewlines',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
// Should show content even without markdown processing
|
|
expect(wrapper.find('.content-text').exists()).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('changelog URL generation', () => {
|
|
it('should generate English changelog URL with version anchor', () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0-beta.1',
|
|
attention: 'medium',
|
|
content: 'Release content',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper()
|
|
const learnMoreLink = wrapper.find('.learn-more-link')
|
|
|
|
// formatVersionAnchor replaces dots with dashes: 1.24.0-beta.1 -> v1-24-0-beta-1
|
|
expect(learnMoreLink.attributes('href')).toBe(
|
|
'https://docs.comfy.org/changelog#v1-24-0-beta-1'
|
|
)
|
|
})
|
|
|
|
it('should generate Chinese changelog URL when locale is zh', () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: 'Release content',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper({
|
|
global: {
|
|
mocks: {
|
|
$t: vi.fn((key: string) => {
|
|
const translations: Record<string, string> = {
|
|
'g.close': 'Close',
|
|
'whatsNewPopup.noReleaseNotes': 'No release notes available',
|
|
'whatsNewPopup.learnMore': 'Learn More'
|
|
}
|
|
return translations[key] || key
|
|
})
|
|
},
|
|
provide: {
|
|
// Mock vue-i18n locale as Chinese
|
|
locale: { value: 'zh' }
|
|
}
|
|
}
|
|
})
|
|
|
|
// Since the locale mocking doesn't work well in tests, just check the English URL for now
|
|
// In a real component test with proper i18n setup, this would show the Chinese URL
|
|
const learnMoreLink = wrapper.find('.learn-more-link')
|
|
expect(learnMoreLink.attributes('href')).toBe(
|
|
'https://docs.comfy.org/changelog#v1-24-0'
|
|
)
|
|
})
|
|
|
|
it('should generate base changelog URL when no version available', () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '',
|
|
attention: 'medium',
|
|
content: 'Release content',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper()
|
|
const learnMoreLink = wrapper.find('.learn-more-link')
|
|
|
|
expect(learnMoreLink.attributes('href')).toBe(
|
|
'https://docs.comfy.org/changelog'
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('popup dismissal', () => {
|
|
it('should call handleWhatsNewSeen and emit event when closed', async () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: 'Release content',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
mockReleaseStore.handleWhatsNewSeen.mockResolvedValue(undefined)
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
// Click close button
|
|
await wrapper.find('.close-button').trigger('click')
|
|
|
|
expect(mockReleaseStore.handleWhatsNewSeen).toHaveBeenCalledWith('1.24.0')
|
|
expect(wrapper.emitted('whats-new-dismissed')).toBeTruthy()
|
|
expect(wrapper.emitted('whats-new-dismissed')).toHaveLength(1)
|
|
})
|
|
|
|
it('should close when learn more link is clicked', async () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: 'Release content',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
mockReleaseStore.handleWhatsNewSeen.mockResolvedValue(undefined)
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
// Click learn more link
|
|
await wrapper.find('.learn-more-link').trigger('click')
|
|
|
|
expect(mockReleaseStore.handleWhatsNewSeen).toHaveBeenCalledWith('1.24.0')
|
|
expect(wrapper.emitted('whats-new-dismissed')).toBeTruthy()
|
|
})
|
|
|
|
it('should handle cases where no release is available during close', async () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = null
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
// Try to close
|
|
await wrapper.find('.close-button').trigger('click')
|
|
|
|
expect(mockReleaseStore.handleWhatsNewSeen).not.toHaveBeenCalled()
|
|
expect(wrapper.emitted('whats-new-dismissed')).toBeTruthy()
|
|
})
|
|
})
|
|
|
|
describe('exposed methods', () => {
|
|
it('should expose show and hide methods', () => {
|
|
const wrapper = createWrapper()
|
|
|
|
expect(wrapper.vm.show).toBeDefined()
|
|
expect(wrapper.vm.hide).toBeDefined()
|
|
expect(typeof wrapper.vm.show).toBe('function')
|
|
expect(typeof wrapper.vm.hide).toBe('function')
|
|
})
|
|
|
|
it('should show popup when show method is called', async () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
// Initially hide it
|
|
wrapper.vm.hide()
|
|
await nextTick()
|
|
expect(wrapper.find('.whats-new-popup-container').exists()).toBe(false)
|
|
|
|
// Show it
|
|
wrapper.vm.show()
|
|
await nextTick()
|
|
expect(wrapper.find('.whats-new-popup-container').exists()).toBe(true)
|
|
})
|
|
|
|
it('should hide popup when hide method is called', async () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
// Initially visible
|
|
expect(wrapper.find('.whats-new-popup-container').exists()).toBe(true)
|
|
|
|
// Hide it
|
|
wrapper.vm.hide()
|
|
await nextTick()
|
|
expect(wrapper.find('.whats-new-popup-container').exists()).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('initialization', () => {
|
|
it('should fetch releases on mount if not already loaded', async () => {
|
|
mockReleaseStore.releases = []
|
|
mockReleaseStore.fetchReleases.mockResolvedValue(undefined)
|
|
|
|
createWrapper()
|
|
|
|
// Wait for onMounted
|
|
await nextTick()
|
|
|
|
expect(mockReleaseStore.fetchReleases).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should not fetch releases if already loaded', async () => {
|
|
mockReleaseStore.releases = [
|
|
{
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium' as const,
|
|
content: 'Content',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
]
|
|
mockReleaseStore.fetchReleases.mockResolvedValue(undefined)
|
|
|
|
createWrapper()
|
|
|
|
// Wait for onMounted
|
|
await nextTick()
|
|
|
|
expect(mockReleaseStore.fetchReleases).not.toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('accessibility', () => {
|
|
it('should have proper aria-label for close button', () => {
|
|
const mockT = vi.fn((key) => (key === 'g.close' ? 'Close' : key))
|
|
vi.doMock('vue-i18n', () => ({
|
|
useI18n: vi.fn(() => ({
|
|
locale: { value: 'en' },
|
|
t: mockT
|
|
}))
|
|
}))
|
|
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: 'Content',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper()
|
|
|
|
expect(wrapper.find('.close-button').attributes('aria-label')).toBe(
|
|
'Close'
|
|
)
|
|
})
|
|
|
|
it('should have proper link attributes for external changelog', () => {
|
|
mockReleaseStore.shouldShowPopup = true
|
|
mockReleaseStore.recentRelease = {
|
|
id: 1,
|
|
project: 'comfyui_frontend',
|
|
version: '1.24.0',
|
|
attention: 'medium',
|
|
content: 'Content',
|
|
published_at: '2023-01-01T00:00:00Z'
|
|
}
|
|
|
|
const wrapper = createWrapper()
|
|
const learnMoreLink = wrapper.find('.learn-more-link')
|
|
|
|
expect(learnMoreLink.attributes('target')).toBe('_blank')
|
|
expect(learnMoreLink.attributes('rel')).toBe('noopener,noreferrer')
|
|
})
|
|
})
|
|
})
|