Files
ComfyUI_frontend/src/composables/useNewMenuItemIndicator.test.ts
pythongosssss 0ab3fdc2c9 Add indicator circle when new unseen menu items are available (#9220)
## Summary

Adds a little indicator circle when new workflow menu items are added
that the user has not seen

## Changes

- **What**: Adds a hidden setting to track menu items flagged as new
that have been seen

## Screenshots (if applicable)

<img width="164" height="120" alt="image"
src="https://github.com/user-attachments/assets/ac36673d-fbf1-42ff-9a9e-1371eb96115b"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9220-Add-indicator-circle-when-new-unseen-menu-items-are-available-3126d73d3650819cb8cde854d6b6510b)
by [Unito](https://www.unito.io)
2026-02-28 12:53:26 -08:00

112 lines
3.3 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('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()
})
})