mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-24 14:45:36 +00:00
*PR Created by the Glary-Bot Agent* --- ## Summary PR #10890 routed the legacy action bar feedback button and the Help Center feedback item to the nightly Typeform survey, but the **default topbar feedback button** in `WorkflowTabs.vue` still called `buildFeedbackUrl()` and opened Zendesk. Since `Comfy.UI.TabBarLayout` defaults to `Default` (not `Legacy`), most Cloud/Nightly users were clicking the WorkflowTabs button and never reaching the Typeform survey — explaining the lack of survey responses. ## Changes - Added a shared `buildFeedbackTypeformUrl(source)` helper in `platform/support/config.ts` that tags the survey URL with: - `distribution`: `ccloud` / `oss-nightly` / `oss` (preserves the build-tagging the old `buildFeedbackUrl()` sent to Zendesk so responses stay segmented) - `source`: `topbar` / `action-bar` / `help-center` (identifies which UI entry point launched the survey) Tags are passed via the URL fragment (Typeform's hidden-field convention), so they reach the survey but are never sent to the server in the request line. - `WorkflowTabs.vue`: replaced `buildFeedbackUrl()` with `buildFeedbackTypeformUrl('topbar')`. - `cloudFeedbackTopbarButton.ts` and `HelpCenterMenuContent.vue`: use the shared builder with their respective source labels instead of inline URL literals. - Removed the now-unused `buildFeedbackUrl()` and `ZENDESK_FEEDBACK_FORM_ID` (knip-clean). `buildSupportUrl()` is preserved — `Comfy.ContactSupport` (the Help Center "Help" item) still routes to Zendesk as before. - Added unit tests for the builder, the WorkflowTabs feedback button, the legacy action bar button, and the Help Center feedback item (covering both the Cloud/Nightly Typeform path and the OSS `Comfy.ContactSupport` fallback). ## Verification - `pnpm format`, `pnpm lint`, `pnpm typecheck`, `pnpm knip`: clean (one pre-existing unrelated lint warning in `useWorkspaceBilling.test.ts`) - `pnpm test:unit` (impacted scope): 506/506 passing, including 13 new tests ## Review Focus - Cloud/Nightly gating in `WorkflowTabs.vue` (`v-if="isCloud || isNightly"`) is unchanged and matches PR #10890's gating philosophy. - The Help Center "Help" item and `Comfy.ContactSupport` command intentionally still route to Zendesk — feedback ≠ support. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11863-fix-route-default-topbar-feedback-button-to-Typeform-3556d73d3650815fb446dac33095d4be) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
187 lines
4.5 KiB
TypeScript
187 lines
4.5 KiB
TypeScript
import { render, screen } from '@testing-library/vue'
|
|
import userEvent from '@testing-library/user-event'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { defineComponent, h, reactive } from 'vue'
|
|
import { createI18n } from 'vue-i18n'
|
|
|
|
import enMessages from '@/locales/en/main.json' with { type: 'json' }
|
|
|
|
import WorkflowTabs from './WorkflowTabs.vue'
|
|
|
|
const distribution = vi.hoisted(() => ({
|
|
isCloud: false,
|
|
isDesktop: false,
|
|
isNightly: false
|
|
}))
|
|
|
|
const tabBarLayout = vi.hoisted(() => ({ value: 'Default' }))
|
|
|
|
vi.mock('@/platform/distribution/types', () => ({
|
|
get isCloud() {
|
|
return distribution.isCloud
|
|
},
|
|
get isDesktop() {
|
|
return distribution.isDesktop
|
|
},
|
|
get isNightly() {
|
|
return distribution.isNightly
|
|
}
|
|
}))
|
|
|
|
vi.mock('@/platform/settings/settingStore', () => ({
|
|
useSettingStore: () => ({
|
|
get: (key: string) =>
|
|
key === 'Comfy.UI.TabBarLayout' ? tabBarLayout.value : undefined
|
|
})
|
|
}))
|
|
|
|
vi.mock('@/composables/auth/useCurrentUser', () => ({
|
|
useCurrentUser: () => ({ isLoggedIn: { value: false } })
|
|
}))
|
|
|
|
vi.mock('@/composables/useFeatureFlags', () => ({
|
|
useFeatureFlags: () => ({ flags: { showSignInButton: false } })
|
|
}))
|
|
|
|
vi.mock('@/composables/element/useOverflowObserver', () => ({
|
|
useOverflowObserver: () => ({
|
|
isOverflowing: { value: false },
|
|
disposed: { value: false },
|
|
checkOverflow: vi.fn(),
|
|
dispose: vi.fn()
|
|
})
|
|
}))
|
|
|
|
vi.mock('@/platform/workflow/core/services/workflowService', () => ({
|
|
useWorkflowService: () => ({
|
|
openWorkflow: vi.fn(),
|
|
closeWorkflow: vi.fn()
|
|
})
|
|
}))
|
|
|
|
vi.mock('@/platform/workflow/management/stores/workflowStore', () => ({
|
|
useWorkflowStore: () =>
|
|
reactive({
|
|
openWorkflows: [],
|
|
activeWorkflow: null
|
|
})
|
|
}))
|
|
|
|
vi.mock('@/stores/commandStore', () => ({
|
|
useCommandStore: () => ({ execute: vi.fn() })
|
|
}))
|
|
|
|
vi.mock('@/stores/workspaceStore', () => ({
|
|
useWorkspaceStore: () => ({ shiftDown: false })
|
|
}))
|
|
|
|
vi.mock('@/utils/mouseDownUtil', () => ({
|
|
whileMouseDown: vi.fn()
|
|
}))
|
|
|
|
vi.mock('./WorkflowOverflowMenu.vue', () => ({
|
|
default: defineComponent({
|
|
name: 'WorkflowOverflowMenuStub',
|
|
render: () => h('div')
|
|
})
|
|
}))
|
|
|
|
vi.mock('./WorkflowTab.vue', () => ({
|
|
default: defineComponent({
|
|
name: 'WorkflowTabStub',
|
|
render: () => h('div')
|
|
})
|
|
}))
|
|
|
|
vi.mock('./CurrentUserButton.vue', () => ({
|
|
default: defineComponent({
|
|
name: 'CurrentUserButtonStub',
|
|
render: () => h('div')
|
|
})
|
|
}))
|
|
|
|
vi.mock('./LoginButton.vue', () => ({
|
|
default: defineComponent({
|
|
name: 'LoginButtonStub',
|
|
render: () => h('div')
|
|
})
|
|
}))
|
|
|
|
function renderComponent() {
|
|
const user = userEvent.setup()
|
|
const i18n = createI18n({
|
|
legacy: false,
|
|
locale: 'en',
|
|
messages: { en: enMessages }
|
|
})
|
|
|
|
const result = render(WorkflowTabs, {
|
|
global: {
|
|
plugins: [i18n],
|
|
directives: {
|
|
tooltip: {}
|
|
}
|
|
}
|
|
})
|
|
|
|
return { user, ...result }
|
|
}
|
|
|
|
describe('WorkflowTabs feedback button', () => {
|
|
let openSpy: ReturnType<typeof vi.spyOn>
|
|
|
|
beforeEach(() => {
|
|
distribution.isCloud = false
|
|
distribution.isDesktop = false
|
|
distribution.isNightly = false
|
|
tabBarLayout.value = 'Default'
|
|
openSpy = vi.spyOn(window, 'open').mockReturnValue(null)
|
|
})
|
|
|
|
afterEach(() => {
|
|
openSpy.mockRestore()
|
|
})
|
|
|
|
it('opens the Typeform survey tagged with topbar source on Cloud', async () => {
|
|
distribution.isCloud = true
|
|
const { user } = renderComponent()
|
|
|
|
await user.click(screen.getByRole('button', { name: 'Feedback' }))
|
|
|
|
expect(openSpy).toHaveBeenCalledWith(
|
|
'https://form.typeform.com/to/q7azbWPi#distribution=ccloud&source=topbar',
|
|
'_blank',
|
|
'noopener,noreferrer'
|
|
)
|
|
})
|
|
|
|
it('opens the Typeform survey tagged with topbar source on Nightly', async () => {
|
|
distribution.isNightly = true
|
|
const { user } = renderComponent()
|
|
|
|
await user.click(screen.getByRole('button', { name: 'Feedback' }))
|
|
|
|
expect(openSpy).toHaveBeenCalledWith(
|
|
'https://form.typeform.com/to/q7azbWPi#distribution=oss-nightly&source=topbar',
|
|
'_blank',
|
|
'noopener,noreferrer'
|
|
)
|
|
})
|
|
|
|
it('does not render the feedback button on non-Cloud/non-Nightly builds', () => {
|
|
renderComponent()
|
|
expect(
|
|
screen.queryByRole('button', { name: 'Feedback' })
|
|
).not.toBeInTheDocument()
|
|
})
|
|
|
|
it('does not render the feedback button when the legacy tab bar is active', () => {
|
|
distribution.isCloud = true
|
|
tabBarLayout.value = 'Legacy'
|
|
renderComponent()
|
|
expect(
|
|
screen.queryByRole('button', { name: 'Feedback' })
|
|
).not.toBeInTheDocument()
|
|
})
|
|
})
|