-
Notifications
You must be signed in to change notification settings - Fork 460
feat: add dynamic Fuse.js options loading for template filtering #7822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5447dfe
da38db7
f6fe5cd
0deba4d
255a621
f3e4de5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { createPinia, setActivePinia } from 'pinia' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { nextTick, ref } from 'vue' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { IFuseOptions } from 'fuse.js' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { TemplateInfo } from '@/platform/workflow/templates/types/template' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -42,13 +43,21 @@ vi.mock('@/platform/telemetry', () => ({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mockGetFuseOptions = vi.hoisted(() => vi.fn()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.mock('@/scripts/api', () => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| api: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getFuseOptions: mockGetFuseOptions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { useTemplateFiltering } = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await import('@/composables/useTemplateFiltering') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| describe('useTemplateFiltering', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| beforeEach(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setActivePinia(createPinia()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.clearAllMocks() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockGetFuseOptions.mockResolvedValue(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| afterEach(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -272,4 +281,118 @@ describe('useTemplateFiltering', () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'beta-pro' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| describe('loadFuseOptions', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('updates fuseOptions when getFuseOptions returns valid options', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const templates = ref<TemplateInfo[]>([ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'test-template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: 'Test template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaType: 'image', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaSubtype: 'png' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const customFuseOptions: IFuseOptions<TemplateInfo> = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| keys: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { name: 'name', weight: 0.5 }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { name: 'description', weight: 0.5 } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| threshold: 0.4, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| includeScore: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockGetFuseOptions.mockResolvedValueOnce(customFuseOptions) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { loadFuseOptions, filteredTemplates } = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useTemplateFiltering(templates) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await loadFuseOptions() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(mockGetFuseOptions).toHaveBeenCalledTimes(1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(filteredTemplates.value).toBeDefined() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+286
to
+314
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Strengthen test assertion to verify options are applied. The test only asserts that 💡 Suggested enhancement it('updates fuseOptions when getFuseOptions returns valid options', async () => {
const templates = ref<TemplateInfo[]>([
{
name: 'test-template',
description: 'Test template',
mediaType: 'image',
mediaSubtype: 'png'
}
])
const customFuseOptions: IFuseOptions<TemplateInfo> = {
keys: [
{ name: 'name', weight: 0.5 },
{ name: 'description', weight: 0.5 }
],
threshold: 0.4,
includeScore: true
}
mockGetFuseOptions.mockResolvedValueOnce(customFuseOptions)
- const { loadFuseOptions, filteredTemplates } =
+ const { loadFuseOptions, filteredTemplates, searchQuery } =
useTemplateFiltering(templates)
await loadFuseOptions()
+
+ // Verify options are applied by testing search behavior
+ searchQuery.value = 'test'
+ await nextTick()
expect(mockGetFuseOptions).toHaveBeenCalledTimes(1)
expect(filteredTemplates.value).toBeDefined()
+ expect(filteredTemplates.value.length).toBeGreaterThan(0)
})📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('does not update fuseOptions when getFuseOptions returns null', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const templates = ref<TemplateInfo[]>([ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'test-template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: 'Test template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaType: 'image', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaSubtype: 'png' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockGetFuseOptions.mockResolvedValueOnce(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { loadFuseOptions, filteredTemplates } = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useTemplateFiltering(templates) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const initialResults = filteredTemplates.value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await loadFuseOptions() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(mockGetFuseOptions).toHaveBeenCalledTimes(1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(filteredTemplates.value).toEqual(initialResults) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('handles errors when getFuseOptions fails', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const templates = ref<TemplateInfo[]>([ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'test-template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: 'Test template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaType: 'image', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaSubtype: 'png' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockGetFuseOptions.mockRejectedValueOnce(new Error('Network error')) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { loadFuseOptions, filteredTemplates } = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useTemplateFiltering(templates) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const initialResults = filteredTemplates.value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await expect(loadFuseOptions()).rejects.toThrow('Network error') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(filteredTemplates.value).toEqual(initialResults) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+339
to
+358
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# First, find the implementation of loadFuseOptions in useTemplateFiltering.ts
rg -nA 20 'loadFuseOptions' src/composables/useTemplateFiltering.ts | head -60Repository: Comfy-Org/ComfyUI_frontend Length of output: 904 🏁 Script executed: #!/bin/bash
# Also check how loadFuseOptions is called in WorkflowTemplateSelectorDialog.vue
rg -nB 5 -A 5 'loadFuseOptions' src/components/WorkflowTemplateSelectorDialog.vueRepository: Comfy-Org/ComfyUI_frontend Length of output: 159 🏁 Script executed: #!/bin/bash
# Check if there's error handling setup around getFuseOptions calls
rg -nB 3 -A 10 'getFuseOptions' src/composables/useTemplateFiltering.tsRepository: Comfy-Org/ComfyUI_frontend Length of output: 538 🏁 Script executed: #!/bin/bash
# Search for imports/usages of useTemplateFiltering to find the component
rg -l 'useTemplateFiltering' src/components/Repository: Comfy-Org/ComfyUI_frontend Length of output: 133 🏁 Script executed: #!/bin/bash
# Look for loadFuseOptions usage across the codebase
rg -nB 5 -A 5 'loadFuseOptions\(\)' src/Repository: Comfy-Org/ComfyUI_frontend Length of output: 1078 🏁 Script executed: #!/bin/bash
# Check the complete context around the Promise.all call for error handling
rg -nB 20 -A 10 'Promise.all' src/components/custom/widget/WorkflowTemplateSelectorDialog.vue | head -80Repository: Comfy-Org/ComfyUI_frontend Length of output: 1047 Test correctly expects error propagation - but implementation lacks error handling. The test is correct: The function should either:
Currently, the function propagates errors without context, and callers in |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| it('recreates Fuse instance when fuseOptions change', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const templates = ref<TemplateInfo[]>([ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'searchable-template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: 'This is a searchable template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaType: 'image', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaSubtype: 'png' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'another-template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: 'Another template', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaType: 'image', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaSubtype: 'png' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { loadFuseOptions, searchQuery, filteredTemplates } = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useTemplateFiltering(templates) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const customFuseOptions = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| keys: [{ name: 'name', weight: 1.0 }], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| threshold: 0.2, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| includeScore: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| includeMatches: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockGetFuseOptions.mockResolvedValueOnce(customFuseOptions) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await loadFuseOptions() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await nextTick() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| searchQuery.value = 'searchable' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await nextTick() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(filteredTemplates.value.length).toBeGreaterThan(0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(mockGetFuseOptions).toHaveBeenCalledTimes(1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+360
to
+396
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Test assertion could be strengthened to verify Fuse options actually affect search behavior. The test at line 380 only asserts 🔎 Stronger test approach it('recreates Fuse instance when fuseOptions change', async () => {
const templates = ref<TemplateInfo[]>([
{
name: 'searchable-template',
description: 'This is a searchable template',
mediaType: 'image',
mediaSubtype: 'png'
},
{
name: 'another-template',
description: 'Another template',
mediaType: 'image',
mediaSubtype: 'png'
}
])
const { loadFuseOptions, searchQuery, filteredTemplates } =
useTemplateFiltering(templates)
+ // Capture baseline results with default options
+ searchQuery.value = 'searchable'
+ await nextTick()
+ const resultsBeforeOptionsLoad = [...filteredTemplates.value]
const customFuseOptions = {
- keys: [{ name: 'name', weight: 1.0 }],
- threshold: 0.2,
+ keys: [{ name: 'description', weight: 1.0 }], // Different key priority
+ threshold: 0.8, // More lenient threshold
includeScore: true,
includeMatches: true
}
mockGetFuseOptions.mockResolvedValueOnce(customFuseOptions)
await loadFuseOptions()
await nextTick()
- searchQuery.value = 'searchable'
+ // Re-trigger search with new options
+ searchQuery.value = 'another'
await nextTick()
- expect(filteredTemplates.value.length).toBeGreaterThan(0)
+ // Verify results changed due to different options
+ expect(filteredTemplates.value).not.toEqual(resultsBeforeOptionsLoad)
+ expect(filteredTemplates.value.length).toBeGreaterThan(0)
expect(mockGetFuseOptions).toHaveBeenCalledTimes(1)
})🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,6 @@ | ||||||||||||||||||||||||||||||||||||
| import { refDebounced, watchDebounced } from '@vueuse/core' | ||||||||||||||||||||||||||||||||||||
| import Fuse from 'fuse.js' | ||||||||||||||||||||||||||||||||||||
| import type { IFuseOptions } from 'fuse.js' | ||||||||||||||||||||||||||||||||||||
| import { computed, ref, watch } from 'vue' | ||||||||||||||||||||||||||||||||||||
| import type { Ref } from 'vue' | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
@@ -8,6 +9,21 @@ import { useTelemetry } from '@/platform/telemetry' | |||||||||||||||||||||||||||||||||||
| import type { TemplateInfo } from '@/platform/workflow/templates/types/template' | ||||||||||||||||||||||||||||||||||||
| import { useTemplateRankingStore } from '@/stores/templateRankingStore' | ||||||||||||||||||||||||||||||||||||
| import { debounce } from 'es-toolkit/compat' | ||||||||||||||||||||||||||||||||||||
| import { api } from '@/scripts/api' | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Fuse.js configuration for fuzzy search | ||||||||||||||||||||||||||||||||||||
| const defaultFuseOptions: IFuseOptions<TemplateInfo> = { | ||||||||||||||||||||||||||||||||||||
| keys: [ | ||||||||||||||||||||||||||||||||||||
| { name: 'name', weight: 0.3 }, | ||||||||||||||||||||||||||||||||||||
| { name: 'title', weight: 0.3 }, | ||||||||||||||||||||||||||||||||||||
| { name: 'description', weight: 0.1 }, | ||||||||||||||||||||||||||||||||||||
| { name: 'tags', weight: 0.2 }, | ||||||||||||||||||||||||||||||||||||
| { name: 'models', weight: 0.3 } | ||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||
| threshold: 0.33, | ||||||||||||||||||||||||||||||||||||
| includeScore: true, | ||||||||||||||||||||||||||||||||||||
| includeMatches: true | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| export function useTemplateFiltering( | ||||||||||||||||||||||||||||||||||||
| templates: Ref<TemplateInfo[]> | TemplateInfo[] | ||||||||||||||||||||||||||||||||||||
|
|
@@ -35,26 +51,14 @@ export function useTemplateFiltering( | |||||||||||||||||||||||||||||||||||
| | 'model-size-low-to-high' | ||||||||||||||||||||||||||||||||||||
| >(settingStore.get('Comfy.Templates.SortBy')) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const fuseOptions = ref<IFuseOptions<TemplateInfo>>(defaultFuseOptions) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const templatesArray = computed(() => { | ||||||||||||||||||||||||||||||||||||
| const templateData = 'value' in templates ? templates.value : templates | ||||||||||||||||||||||||||||||||||||
| return Array.isArray(templateData) ? templateData : [] | ||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Fuse.js configuration for fuzzy search | ||||||||||||||||||||||||||||||||||||
| const fuseOptions = { | ||||||||||||||||||||||||||||||||||||
| keys: [ | ||||||||||||||||||||||||||||||||||||
| { name: 'name', weight: 0.3 }, | ||||||||||||||||||||||||||||||||||||
| { name: 'title', weight: 0.3 }, | ||||||||||||||||||||||||||||||||||||
| { name: 'description', weight: 0.1 }, | ||||||||||||||||||||||||||||||||||||
| { name: 'tags', weight: 0.2 }, | ||||||||||||||||||||||||||||||||||||
| { name: 'models', weight: 0.3 } | ||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||
| threshold: 0.33, | ||||||||||||||||||||||||||||||||||||
| includeScore: true, | ||||||||||||||||||||||||||||||||||||
| includeMatches: true | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const fuse = computed(() => new Fuse(templatesArray.value, fuseOptions)) | ||||||||||||||||||||||||||||||||||||
| const fuse = computed(() => new Fuse(templatesArray.value, fuseOptions.value)) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const availableModels = computed(() => { | ||||||||||||||||||||||||||||||||||||
| const modelSet = new Set<string>() | ||||||||||||||||||||||||||||||||||||
|
|
@@ -272,6 +276,13 @@ export function useTemplateFiltering( | |||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||
| }, 500) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const loadFuseOptions = async () => { | ||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: Is this something that we could just bake into the composable?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. plan to handle
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By now, there is no scenario to re-fetch the fuse options. |
||||||||||||||||||||||||||||||||||||
| const fetchedOptions = await api.getFuseOptions() | ||||||||||||||||||||||||||||||||||||
| if (fetchedOptions) { | ||||||||||||||||||||||||||||||||||||
| fuseOptions.value = fetchedOptions | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+279
to
+284
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CRITICAL: Missing error handling despite multiple reviews. This function lacks try-catch error handling, causing errors to propagate and break template loading (see related comment on 🔧 Required fix with graceful fallback const loadFuseOptions = async () => {
+ try {
const fetchedOptions = await api.getFuseOptions()
if (fetchedOptions) {
fuseOptions.value = fetchedOptions
}
+ } catch (error) {
+ console.warn('Failed to load Fuse options, using defaults:', error)
+ // fuseOptions.value remains at defaultFuseOptions
+ }
}Based on coding guidelines requiring proper error handling in TypeScript files and previous reviewer feedback. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the try catch handle has been done in |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Watch for filter changes and track them | ||||||||||||||||||||||||||||||||||||
| watch( | ||||||||||||||||||||||||||||||||||||
| [searchQuery, selectedModels, selectedUseCases, selectedRunsOn, sortBy], | ||||||||||||||||||||||||||||||||||||
|
|
@@ -344,6 +355,7 @@ export function useTemplateFiltering( | |||||||||||||||||||||||||||||||||||
| resetFilters, | ||||||||||||||||||||||||||||||||||||
| removeModelFilter, | ||||||||||||||||||||||||||||||||||||
| removeUseCaseFilter, | ||||||||||||||||||||||||||||||||||||
| removeRunsOnFilter | ||||||||||||||||||||||||||||||||||||
| removeRunsOnFilter, | ||||||||||||||||||||||||||||||||||||
| loadFuseOptions | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,7 +10,10 @@ import type { | |||||||||||||||||||||||||||||||
| } from '@/platform/assets/schemas/assetSchema' | ||||||||||||||||||||||||||||||||
| import { isCloud } from '@/platform/distribution/types' | ||||||||||||||||||||||||||||||||
| import { useToastStore } from '@/platform/updates/common/toastStore' | ||||||||||||||||||||||||||||||||
| import { type WorkflowTemplates } from '@/platform/workflow/templates/types/template' | ||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||
| type TemplateInfo, | ||||||||||||||||||||||||||||||||
| type WorkflowTemplates | ||||||||||||||||||||||||||||||||
| } from '@/platform/workflow/templates/types/template' | ||||||||||||||||||||||||||||||||
| import type { | ||||||||||||||||||||||||||||||||
| ComfyApiWorkflow, | ||||||||||||||||||||||||||||||||
| ComfyWorkflowJSON, | ||||||||||||||||||||||||||||||||
|
|
@@ -51,6 +54,7 @@ import type { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' | |||||||||||||||||||||||||||||||
| import type { AuthHeader } from '@/types/authTypes' | ||||||||||||||||||||||||||||||||
| import type { NodeExecutionId } from '@/types/nodeIdentification' | ||||||||||||||||||||||||||||||||
| import { fetchHistory } from '@/platform/remote/comfyui/history' | ||||||||||||||||||||||||||||||||
| import type { IFuseOptions } from 'fuse.js' | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| interface QueuePromptRequestBody { | ||||||||||||||||||||||||||||||||
| client_id: string | ||||||||||||||||||||||||||||||||
|
|
@@ -1269,6 +1273,29 @@ export class ComfyApi extends EventTarget { | |||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||
| * Gets the Fuse options from the server. | ||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||
| * @returns The Fuse options, or null if not found or invalid | ||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||
| async getFuseOptions(): Promise<IFuseOptions<TemplateInfo> | null> { | ||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||
| const res = await axios.get( | ||||||||||||||||||||||||||||||||
| this.fileURL('/templates/fuse_options.json'), | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||||
| 'Content-Type': 'application/json' | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
Comment on lines
+1286
to
+1288
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Remove or replace Content-Type header in GET request. The ♻️ Option 1: Use Accept header instead const res = await axios.get(
this.fileURL('/templates/fuse_options.json'),
{
headers: {
- 'Content-Type': 'application/json'
+ 'Accept': 'application/json'
}
}
)♻️ Option 2: Remove the headers entirely (recommended)Since you're already validating the response content-type on line 1291, the request header is unnecessary: const res = await axios.get(
- this.fileURL('/templates/fuse_options.json'),
- {
- headers: {
- 'Content-Type': 'application/json'
- }
- }
+ this.fileURL('/templates/fuse_options.json')
)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
| const contentType = res.headers['content-type'] | ||||||||||||||||||||||||||||||||
| return contentType?.includes('application/json') ? res.data : null | ||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||
| console.error('Error loading fuse options:', error) | ||||||||||||||||||||||||||||||||
| return null | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||
| * Gets the custom nodes i18n data from the server. | ||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional: Instead of hoisting it separately, if you instantiate it within the mock module you can just import it like you would otherwise and get the same mock here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's easier to assert the fuseOptions with valid data, error state or null data, by hoisting it separately, since fuseOptions not be exported