fix(web): draft sync of snippet

This commit is contained in:
JzoNg
2026-05-25 15:44:27 +08:00
parent 7c0be7f905
commit bba3a1bcee
2 changed files with 106 additions and 4 deletions

View File

@@ -0,0 +1,101 @@
import type { SnippetWorkflow } from '@/types/snippet'
import { renderHook, waitFor } from '@testing-library/react'
import { useSnippetRefreshDraft } from '../use-snippet-refresh-draft'
const mockFetchSnippetDraftWorkflow = vi.fn()
const mockHandleUpdateWorkflowCanvas = vi.fn()
const mockSnippetSetState = vi.fn()
const mockSetDraftUpdatedAt = vi.fn()
const mockSetIsSyncingWorkflowDraft = vi.fn()
const mockSetSyncWorkflowDraftHash = vi.fn()
const workflowStoreState = {
setDraftUpdatedAt: mockSetDraftUpdatedAt,
setIsSyncingWorkflowDraft: mockSetIsSyncingWorkflowDraft,
setSyncWorkflowDraftHash: mockSetSyncWorkflowDraftHash,
}
vi.mock('@/service/use-snippet-workflows', () => ({
fetchSnippetDraftWorkflow: (...args: unknown[]) => mockFetchSnippetDraftWorkflow(...args),
}))
vi.mock('@/app/components/workflow/hooks', () => ({
useWorkflowUpdate: () => ({
handleUpdateWorkflowCanvas: mockHandleUpdateWorkflowCanvas,
}),
}))
vi.mock('@/app/components/workflow/store', () => ({
useWorkflowStore: () => ({
getState: () => workflowStoreState,
}),
}))
vi.mock('../../store', () => ({
useSnippetDetailStore: {
setState: (...args: unknown[]) => mockSnippetSetState(...args),
},
}))
const createDraftWorkflow = (overrides: Partial<SnippetWorkflow> = {}): SnippetWorkflow => ({
id: 'draft-1',
graph: {
nodes: [{ id: 'node-1' }],
edges: [],
viewport: { x: 10, y: 20, zoom: 1.2 },
},
features: {},
input_fields: [],
hash: 'draft-hash',
created_at: 1_712_300_000,
updated_at: 1_712_345_678,
...overrides,
} as SnippetWorkflow)
describe('useSnippetRefreshDraft', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should refresh the draft workflow through the silent draft fetcher', async () => {
const draftWorkflow = createDraftWorkflow()
const onSuccess = vi.fn()
mockFetchSnippetDraftWorkflow.mockResolvedValueOnce(draftWorkflow)
const { result } = renderHook(() => useSnippetRefreshDraft('snippet-1'))
result.current.handleRefreshWorkflowDraft(onSuccess)
await waitFor(() => {
expect(mockHandleUpdateWorkflowCanvas).toHaveBeenCalledWith({
nodes: [{ id: 'node-1' }],
edges: [],
viewport: { x: 10, y: 20, zoom: 1.2 },
})
})
expect(mockFetchSnippetDraftWorkflow).toHaveBeenCalledWith('snippet-1')
expect(mockSnippetSetState).toHaveBeenCalledWith({
fields: [],
})
expect(mockSetSyncWorkflowDraftHash).toHaveBeenCalledWith('draft-hash')
expect(mockSetDraftUpdatedAt).toHaveBeenCalledWith(1_712_345_678)
expect(onSuccess).toHaveBeenCalledWith(draftWorkflow)
expect(mockSetIsSyncingWorkflowDraft).toHaveBeenNthCalledWith(1, true)
expect(mockSetIsSyncingWorkflowDraft).toHaveBeenLastCalledWith(false)
})
it('should silently finish when the draft workflow does not exist yet', async () => {
mockFetchSnippetDraftWorkflow.mockResolvedValueOnce(undefined)
const { result } = renderHook(() => useSnippetRefreshDraft('snippet-1'))
result.current.handleRefreshWorkflowDraft()
await waitFor(() => {
expect(mockSetIsSyncingWorkflowDraft).toHaveBeenLastCalledWith(false)
})
expect(mockFetchSnippetDraftWorkflow).toHaveBeenCalledWith('snippet-1')
expect(mockHandleUpdateWorkflowCanvas).not.toHaveBeenCalled()
expect(mockSnippetSetState).not.toHaveBeenCalled()
})
})

View File

@@ -4,7 +4,7 @@ import type { SnippetWorkflow } from '@/types/snippet'
import { useCallback } from 'react'
import { useWorkflowUpdate } from '@/app/components/workflow/hooks'
import { useWorkflowStore } from '@/app/components/workflow/store'
import { consoleClient } from '@/service/client'
import { fetchSnippetDraftWorkflow } from '@/service/use-snippet-workflows'
import { useSnippetDetailStore } from '../store'
export const useSnippetRefreshDraft = (snippetId: string) => {
@@ -22,9 +22,10 @@ export const useSnippetRefreshDraft = (snippetId: string) => {
return
setIsSyncingWorkflowDraft(true)
consoleClient.snippets.draftWorkflow({
params: { snippetId },
}).then((response) => {
fetchSnippetDraftWorkflow(snippetId).then((response) => {
if (!response)
return
const inputFields = Array.isArray(response.input_fields)
? response.input_fields as SnippetInputField[]
: []