File size: 3,836 Bytes
7312c42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { act } from '@testing-library/react'
import type { ComfyApp } from '@comfyorg/comfyui-frontend-types'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { installProjectSamplingPreview } from '@/lib/project-sampling-preview-node'

const previewState = vi.hoisted(() => ({
  props: null as null | {
    interactive?: boolean
    onVisibilityChange?: (visible: boolean) => void
  },
}))

vi.mock('@/components/widgets/SamplingPreviewWidget', () => ({
  SamplingPreviewWidget: (props: typeof previewState.props) => {
    previewState.props = props
    return <div data-testid="sampling-preview" />
  },
}))

interface TestWidget {
  computedHeight?: number
  hidden?: boolean
  options: {
    getMinHeight: () => number
    getMaxHeight: () => number
  }
}

describe('installProjectSamplingPreview', () => {
  const app = {} as ComfyApp

  beforeEach(() => {
    previewState.props = null
    vi.stubGlobal('requestAnimationFrame', vi.fn((callback: FrameRequestCallback) => {
      callback(0)
      return 1
    }))
  })

  function createNodeType() {
    const host = document.createElement('div')
    document.body.append(host)
    let widget: TestWidget | undefined
    const node = {
      id: 42,
      size: [640, 400] as [number, number],
      graph: { setDirtyCanvas: vi.fn() },
      onResize: vi.fn(),
      setSize: vi.fn(function setSize(this: { size: [number, number] }, size: [number, number]) {
        this.size = size
      }),
      addDOMWidget: vi.fn((
        _name: string,
        _type: string,
        container: HTMLDivElement,
        options: TestWidget['options'],
      ) => {
        host.append(container)
        widget = { options }
        return widget
      }),
    }
    class NodeType {}
    Object.assign(NodeType.prototype, node)
    return { NodeType, host, node, getWidget: () => widget }
  }

  it('only installs on the multitrack project node', () => {
    const { NodeType, node } = createNodeType()
    installProjectSamplingPreview(NodeType, { name: 'easy multitrackEditor' }, app)

    const instance = new NodeType() as typeof node & { onNodeCreated?: () => void }
    act(() => instance.onNodeCreated?.())

    expect(node.addDOMWidget).not.toHaveBeenCalled()
  })

  it('stays inside the node and changes from a tiny slot to a bounded preview', async () => {
    const { NodeType, host, node, getWidget } = createNodeType()
    installProjectSamplingPreview(NodeType, { name: 'easy multitrackProject' }, app)

    const instance = new NodeType() as typeof node & { onNodeCreated?: () => void }
    await act(async () => instance.onNodeCreated?.())

    const widget = getWidget()
    const container = host.firstElementChild as HTMLDivElement
    expect(widget?.hidden).toBe(false)
    expect(widget?.options.getMinHeight()).toBe(8)
    expect(widget?.options.getMaxHeight()).toBe(8)
    expect(container.hidden).toBe(true)
    expect(container.style.position).toBe('relative')
    expect(container.style.height).toBe('280px')
    expect(host.style.maxHeight).toBe('8px')
    expect(host.style.pointerEvents).toBe('none')
    expect(previewState.props?.interactive).toBeUndefined()

    act(() => previewState.props?.onVisibilityChange?.(true))

    expect(widget?.options.getMinHeight()).toBe(280)
    expect(widget?.options.getMaxHeight()).toBe(280)
    expect(container.hidden).toBe(false)
    expect(host.style.maxHeight).toBe('280px')
    expect(host.style.overflow).toBe('hidden')
    expect(host.style.pointerEvents).toBe('auto')
    expect(node.setSize).toHaveBeenCalledWith([640, 672])
    expect(node.onResize).toHaveBeenCalledWith([640, 672])
    expect(node.graph.setDirtyCanvas).toHaveBeenCalledWith(true, true)

    act(() => previewState.props?.onVisibilityChange?.(false))
    expect(node.setSize).toHaveBeenLastCalledWith([640, 400])
  })
})