Files
ComfyUI_frontend/src/composables/useNewMenuItemIndicator.test.ts
pythongosssss b18a0713db feat: App mode enter builder menu item (#9341)
## Summary

Adds enter builder menu item for easier access to app builder. 
Fixes issues with seen item tracking

## Changes

- **What**: 
- add enter builder menu item
- change non visible items to still be returned as part of the array, so
they are not incorrectly removed from the seen-items tracking
- split toggle-app-mode into two stable items

## Screenshots (if applicable)

<img width="309" height="526" alt="image"
src="https://github.com/user-attachments/assets/69affc2c-34ab-45eb-b47b-efacb8a20b99"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9341-feat-App-mode-enter-builder-menu-item-3176d73d365081a9a7e7cf1a1986354f)
by [Unito](https://www.unito.io)
2026-03-03 08:35:47 -08:00

186 lines
5.1 KiB
TypeScript

import { createPinia, setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { useNewMenuItemIndicator } from '@/composables/useNewMenuItemIndicator'
import type { WorkflowMenuItem } from '@/types/workflowMenuItem'
const mockSettingStore = vi.hoisted(() => ({
get: vi.fn((): string[] => []),
set: vi.fn()
}))
vi.mock('@/platform/settings/settingStore', () => ({
useSettingStore: vi.fn(() => mockSettingStore)
}))
function createItems(...ids: string[]): WorkflowMenuItem[] {
return ids.map((id) => ({
id,
label: `Label for ${id}`,
icon: 'pi pi-test',
command: vi.fn(),
isNew: true,
badge: 'BETA'
}))
}
describe('useNewMenuItemIndicator', () => {
beforeEach(() => {
setActivePinia(createPinia())
vi.clearAllMocks()
mockSettingStore.get.mockReturnValue([])
})
it('reports unseen items when no items have been seen', () => {
const items = createItems('feature-a')
const { hasUnseenItems } = useNewMenuItemIndicator(() => items)
expect(hasUnseenItems.value).toBe(true)
})
it('reports no unseen items when all new items are already seen', () => {
mockSettingStore.get.mockReturnValue(['feature-a'])
const items = createItems('feature-a')
const { hasUnseenItems } = useNewMenuItemIndicator(() => items)
expect(hasUnseenItems.value).toBe(false)
})
it('reports unseen when some new items are not yet seen', () => {
mockSettingStore.get.mockReturnValue(['feature-a'])
const items = createItems('feature-a', 'feature-b')
const { hasUnseenItems } = useNewMenuItemIndicator(() => items)
expect(hasUnseenItems.value).toBe(true)
})
it('reports no unseen items when menu has no isNew items', () => {
const items: WorkflowMenuItem[] = [
{ id: 'regular', label: 'Regular', icon: 'pi pi-test', command: vi.fn() }
]
const { hasUnseenItems } = useNewMenuItemIndicator(() => items)
expect(hasUnseenItems.value).toBe(false)
})
it('ignores separators', () => {
const items: WorkflowMenuItem[] = [
{ separator: true },
...createItems('feature-a')
]
const { hasUnseenItems } = useNewMenuItemIndicator(() => items)
expect(hasUnseenItems.value).toBe(true)
})
it('markAsSeen persists current new item ids', () => {
const items = createItems('feature-a', 'feature-b')
const { markAsSeen } = useNewMenuItemIndicator(() => items)
markAsSeen()
expect(mockSettingStore.set).toHaveBeenCalledWith(
'Comfy.WorkflowActions.SeenItems',
['feature-a', 'feature-b']
)
})
it('markAsSeen replaces stale entries with current new items', () => {
mockSettingStore.get.mockReturnValue(['old-feature', 'feature-a'])
const items = createItems('feature-a')
const { markAsSeen } = useNewMenuItemIndicator(() => items)
markAsSeen()
expect(mockSettingStore.set).toHaveBeenCalledWith(
'Comfy.WorkflowActions.SeenItems',
['feature-a']
)
})
it('does not count hidden items as unseen', () => {
const items: WorkflowMenuItem[] = [
{
id: 'hidden-feature',
label: 'Hidden',
icon: 'pi pi-test',
command: vi.fn(),
isNew: true,
badge: 'BETA',
visible: false
}
]
const { hasUnseenItems } = useNewMenuItemIndicator(() => items)
expect(hasUnseenItems.value).toBe(false)
})
it('markAsSeen does not include never-seen hidden items', () => {
const items: WorkflowMenuItem[] = [
...createItems('feature-a'),
{
id: 'hidden-feature',
label: 'Hidden',
icon: 'pi pi-test',
command: vi.fn(),
isNew: true,
badge: 'BETA',
visible: false
}
]
const { markAsSeen } = useNewMenuItemIndicator(() => items)
markAsSeen()
expect(mockSettingStore.set).toHaveBeenCalledWith(
'Comfy.WorkflowActions.SeenItems',
['feature-a']
)
})
it('markAsSeen retains previously-seen hidden items', () => {
mockSettingStore.get.mockReturnValue(['hidden-feature'])
const items: WorkflowMenuItem[] = [
...createItems('feature-a'),
{
id: 'hidden-feature',
label: 'Hidden',
icon: 'pi pi-test',
command: vi.fn(),
isNew: true,
badge: 'BETA',
visible: false
}
]
const { markAsSeen } = useNewMenuItemIndicator(() => items)
markAsSeen()
expect(mockSettingStore.set).toHaveBeenCalledWith(
'Comfy.WorkflowActions.SeenItems',
['feature-a', 'hidden-feature']
)
})
it('markAsSeen skips write when stored list already matches', () => {
mockSettingStore.get.mockReturnValue(['feature-a', 'feature-b'])
const items = createItems('feature-a', 'feature-b')
const { markAsSeen } = useNewMenuItemIndicator(() => items)
markAsSeen()
expect(mockSettingStore.set).not.toHaveBeenCalled()
})
it('markAsSeen does nothing when there are no new items', () => {
const items: WorkflowMenuItem[] = [
{ id: 'regular', label: 'Regular', icon: 'pi pi-test', command: vi.fn() }
]
const { markAsSeen } = useNewMenuItemIndicator(() => items)
markAsSeen()
expect(mockSettingStore.set).not.toHaveBeenCalled()
})
})