104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
createAIDataModalDraftState,
|
|
mergeAIDataModalDraftStateByDirty,
|
|
} from '@/app/[locale]/workspace/[projectId]/modes/novel-promotion/components/storyboard/hooks/useAIDataModalState'
|
|
|
|
describe('useAIDataModalState optimistic sync helpers', () => {
|
|
it('keeps dirty fields when server data refreshes', () => {
|
|
const localDraft = createAIDataModalDraftState({
|
|
initialShotType: 'Close-up',
|
|
initialCameraMove: 'Push in',
|
|
initialDescription: 'user typing draft',
|
|
initialVideoPrompt: 'prompt-a',
|
|
initialPhotographyRules: null,
|
|
initialActingNotes: null,
|
|
})
|
|
|
|
const serverDraft = createAIDataModalDraftState({
|
|
initialShotType: 'Wide',
|
|
initialCameraMove: 'Pan left',
|
|
initialDescription: 'server-updated-desc',
|
|
initialVideoPrompt: 'prompt-b',
|
|
initialPhotographyRules: null,
|
|
initialActingNotes: null,
|
|
})
|
|
|
|
const merged = mergeAIDataModalDraftStateByDirty(
|
|
localDraft,
|
|
serverDraft,
|
|
new Set(['description']),
|
|
)
|
|
|
|
expect(merged.description).toBe('user typing draft')
|
|
expect(merged.shotType).toBe('Wide')
|
|
expect(merged.cameraMove).toBe('Pan left')
|
|
expect(merged.videoPrompt).toBe('prompt-b')
|
|
})
|
|
|
|
it('syncs non-dirty nested fields from server', () => {
|
|
const localDraft = createAIDataModalDraftState({
|
|
initialShotType: 'A',
|
|
initialCameraMove: 'B',
|
|
initialDescription: 'C',
|
|
initialVideoPrompt: 'D',
|
|
initialPhotographyRules: {
|
|
scene_summary: 'local scene',
|
|
lighting: {
|
|
direction: 'front',
|
|
quality: 'soft',
|
|
},
|
|
characters: [{
|
|
name: 'hero',
|
|
screen_position: 'left',
|
|
posture: 'standing',
|
|
facing: 'camera',
|
|
}],
|
|
depth_of_field: 'deep',
|
|
color_tone: 'warm',
|
|
},
|
|
initialActingNotes: [{
|
|
name: 'hero',
|
|
acting: 'smile',
|
|
}],
|
|
})
|
|
|
|
const serverDraft = createAIDataModalDraftState({
|
|
initialShotType: 'A2',
|
|
initialCameraMove: 'B2',
|
|
initialDescription: 'C2',
|
|
initialVideoPrompt: 'D2',
|
|
initialPhotographyRules: {
|
|
scene_summary: 'server scene',
|
|
lighting: {
|
|
direction: 'back',
|
|
quality: 'hard',
|
|
},
|
|
characters: [{
|
|
name: 'hero',
|
|
screen_position: 'center',
|
|
posture: 'running',
|
|
facing: 'right',
|
|
}],
|
|
depth_of_field: 'shallow',
|
|
color_tone: 'cool',
|
|
},
|
|
initialActingNotes: [{
|
|
name: 'hero',
|
|
acting: 'angry',
|
|
}],
|
|
})
|
|
|
|
const merged = mergeAIDataModalDraftStateByDirty(
|
|
localDraft,
|
|
serverDraft,
|
|
new Set(['videoPrompt']),
|
|
)
|
|
|
|
expect(merged.videoPrompt).toBe('D')
|
|
expect(merged.photographyRules?.scene_summary).toBe('server scene')
|
|
expect(merged.photographyRules?.lighting.direction).toBe('back')
|
|
expect(merged.actingNotes[0]?.acting).toBe('angry')
|
|
})
|
|
})
|