mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-23 06:10:32 +00:00
… (issue #11092 phase 4b)
## Summary
Part of #11092 — Phase 4b: remove 2 `@ts-expect-error` suppressions from
`CustomizationDialog.vue`.
## Changes
`selectedIcon` ref initialisation and `resetCustomization` assignment
both suppressed a type error on `Array.find()` returning `T |
undefined`.
**Why**
`Array.find()` has no way to statically guarantee a match, so its return
type is always `T | undefined`. Both usages were searching `iconOptions`
— a literal array of 8 entries declared in the same scope — and
TypeScript could not prove that the searched value would always be
found, even though at runtime it always is (the default icon value is
defined from `iconOptions[0]`).
**How**
Added `iconOptions[0]` as a final fallback via `??` in both places.
Because `iconOptions` is a non-empty literal array, `iconOptions[0]` is
provably non-null to TypeScript, which makes the overall expression type
`T` and satisfies the assignment. The explicit generic on `ref<{ name:
string; value: string }>` was also dropped — TypeScript infers the type
correctly from the non-nullable initialiser. In `resetCustomization`,
`||` was replaced with `??` since the values being null-coalesced are
objects (never falsy), making `??` the semantically precise operator for
this case.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Low risk: UI-only refactor that adds explicit fallbacks for
`Array.find()` results and introduces a small unit test suite; behavior
should remain the same except for safer handling of unexpected icon
values.
>
> **Overview**
> Removes two `@ts-expect-error` suppressions in
`CustomizationDialog.vue` by making `selectedIcon` initialization and
`resetCustomization` use a guaranteed fallback (`iconOptions[0]`) via
`??`, ensuring the selected icon is never `undefined`.
>
> Adds `CustomizationDialog.test.ts` to verify `confirm` emits the
expected icon/color for default, provided initial values, and an invalid
`initialIcon` fallback.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f77addf713. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11339-refactor-remove-ts-expect-error-suppressions-in-CustomizationDialog-3456d73d36508165865ac569e047db2e)
by [Unito](https://www.unito.io)
105 lines
3.0 KiB
TypeScript
105 lines
3.0 KiB
TypeScript
import { render, screen } from '@testing-library/vue'
|
|
import userEvent from '@testing-library/user-event'
|
|
import { describe, expect, it, vi } from 'vitest'
|
|
import { createI18n } from 'vue-i18n'
|
|
|
|
import CustomizationDialog from './CustomizationDialog.vue'
|
|
|
|
const DEFAULT_ICON = 'pi-bookmark-fill'
|
|
const DEFAULT_COLOR = '#a1a1aa'
|
|
|
|
vi.mock('@/stores/nodeBookmarkStore', () => ({
|
|
useNodeBookmarkStore: () => ({
|
|
defaultBookmarkIcon: DEFAULT_ICON,
|
|
defaultBookmarkColor: DEFAULT_COLOR,
|
|
bookmarksCustomization: {}
|
|
})
|
|
}))
|
|
|
|
vi.mock('primevue/dialog', () => ({
|
|
default: {
|
|
name: 'Dialog',
|
|
template: '<div v-if="visible"><slot /><slot name="footer" /></div>',
|
|
props: ['visible']
|
|
}
|
|
}))
|
|
|
|
vi.mock('primevue/selectbutton', () => ({
|
|
default: {
|
|
name: 'SelectButton',
|
|
template: '<div />',
|
|
props: ['modelValue', 'options']
|
|
}
|
|
}))
|
|
|
|
vi.mock('primevue/divider', () => ({
|
|
default: { name: 'Divider', template: '<hr />' }
|
|
}))
|
|
|
|
vi.mock('@/components/common/ColorCustomizationSelector.vue', () => ({
|
|
default: {
|
|
name: 'ColorCustomizationSelector',
|
|
template: '<div />',
|
|
props: ['modelValue', 'colorOptions']
|
|
}
|
|
}))
|
|
|
|
vi.mock('@/components/ui/button/Button.vue', () => ({
|
|
default: {
|
|
name: 'Button',
|
|
template: `<button @click="$emit('click')"><slot /></button>`,
|
|
emits: ['click']
|
|
}
|
|
}))
|
|
|
|
const i18n = createI18n({ legacy: false, locale: 'en', messages: { en: {} } })
|
|
|
|
function renderDialog(extraProps: Record<string, unknown> = {}) {
|
|
const onConfirm = vi.fn()
|
|
render(CustomizationDialog, {
|
|
global: { plugins: [i18n] },
|
|
props: { modelValue: true, onConfirm, ...extraProps }
|
|
})
|
|
return { onConfirm }
|
|
}
|
|
|
|
describe('CustomizationDialog', () => {
|
|
describe('confirmCustomization', () => {
|
|
it('emits confirm with default icon and color when no initial values provided', async () => {
|
|
const user = userEvent.setup()
|
|
const { onConfirm } = renderDialog()
|
|
|
|
await user.click(screen.getByText('g.confirm'))
|
|
|
|
expect(onConfirm).toHaveBeenCalledWith(DEFAULT_ICON, DEFAULT_COLOR)
|
|
})
|
|
|
|
it('emits confirm with matching initialIcon when provided', async () => {
|
|
const user = userEvent.setup()
|
|
const { onConfirm } = renderDialog({ initialIcon: 'pi-star' })
|
|
|
|
await user.click(screen.getByText('g.confirm'))
|
|
|
|
expect(onConfirm).toHaveBeenCalledWith('pi-star', DEFAULT_COLOR)
|
|
})
|
|
|
|
it('falls back to default icon when initialIcon does not match any option', async () => {
|
|
const user = userEvent.setup()
|
|
const { onConfirm } = renderDialog({ initialIcon: 'pi-nonexistent' })
|
|
|
|
await user.click(screen.getByText('g.confirm'))
|
|
|
|
expect(onConfirm).toHaveBeenCalledWith(DEFAULT_ICON, DEFAULT_COLOR)
|
|
})
|
|
|
|
it('emits confirm with initialColor when provided', async () => {
|
|
const user = userEvent.setup()
|
|
const { onConfirm } = renderDialog({ initialColor: '#007bff' })
|
|
|
|
await user.click(screen.getByText('g.confirm'))
|
|
|
|
expect(onConfirm).toHaveBeenCalledWith(DEFAULT_ICON, '#007bff')
|
|
})
|
|
})
|
|
})
|