File size: 3,757 Bytes
1f21206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import '@testing-library/jest-dom'

vi.mock('../../i18n', () => ({
  useTranslation: () => (key: string, params?: Record<string, string | number>) => {
    const template = {
      'openProject.openIn': 'Open in {target}',
      'openProject.openProject': 'Open project',
      'openProject.openFailed': 'Could not open project',
    }[key] ?? key

    if (!params) return template
    return Object.entries(params).reduce(
      (text, [name, value]) => text.replaceAll(`{${name}}`, String(value)),
      template,
    )
  },
}))

const storeMocks = vi.hoisted(() => ({
  ensureTargets: vi.fn(),
  openTarget: vi.fn(),
  state: {
    targets: [] as Array<{
      id: string
      kind: 'ide' | 'file_manager'
      label: string
      icon: string
      iconUrl?: string
      platform: string
    }>,
    primaryTargetId: null as string | null,
    loading: false,
    error: null as string | null,
  },
}))

vi.mock('../../stores/openTargetStore', () => ({
  useOpenTargetStore: (
    selector: (state: typeof storeMocks.state & {
      ensureTargets: typeof storeMocks.ensureTargets
      openTarget: typeof storeMocks.openTarget
    }) => unknown,
  ) => selector({
    ...storeMocks.state,
    ensureTargets: storeMocks.ensureTargets,
    openTarget: storeMocks.openTarget,
  }),
}))

import { OpenProjectMenu } from './OpenProjectMenu'

describe('OpenProjectMenu', () => {
  beforeEach(() => {
    storeMocks.ensureTargets.mockReset()
    storeMocks.openTarget.mockReset()
    storeMocks.state = {
      targets: [],
      primaryTargetId: null,
      loading: false,
      error: null,
    }
  })

  it('renders a single Finder action when only file manager is detected', async () => {
    storeMocks.state.targets = [{ id: 'finder', kind: 'file_manager', label: 'Finder', icon: 'finder', platform: 'darwin' }]
    storeMocks.state.primaryTargetId = 'finder'
    storeMocks.openTarget.mockResolvedValue(undefined)

    render(<OpenProjectMenu path="/repo" />)

    await waitFor(() => expect(storeMocks.ensureTargets).toHaveBeenCalled())
    await act(async () => {
      fireEvent.click(screen.getByRole('button', { name: 'Open in Finder' }))
    })

    expect(storeMocks.openTarget).toHaveBeenCalledWith('finder', '/repo')
    expect(screen.queryByRole('menu')).not.toBeInTheDocument()
  })

  it('renders a dropdown with detected IDEs and Finder', async () => {
    storeMocks.state.targets = [
      { id: 'vscode', kind: 'ide', label: 'VS Code', icon: 'vscode', iconUrl: '/api/open-targets/icons/vscode', platform: 'darwin' },
      { id: 'finder', kind: 'file_manager', label: 'Finder', icon: 'finder', iconUrl: '/api/open-targets/icons/finder', platform: 'darwin' },
    ]
    storeMocks.state.primaryTargetId = 'vscode'
    storeMocks.openTarget.mockResolvedValue(undefined)

    const { container } = render(<OpenProjectMenu path="/repo" />)

    await act(async () => {
      fireEvent.click(screen.getByRole('button', { name: 'Open project' }))
    })
    expect(screen.getByRole('menu')).toBeInTheDocument()
    expect([
      ...Array.from(container.querySelectorAll('img')),
      ...Array.from(document.body.querySelectorAll('[role="menu"] img')),
    ].map((img) => img.getAttribute('src'))).toContain('/api/open-targets/icons/vscode')
    await act(async () => {
      fireEvent.click(screen.getByRole('menuitem', { name: 'Finder' }))
    })

    expect(storeMocks.openTarget).toHaveBeenCalledWith('finder', '/repo')
  })

  it('does not render without a path', () => {
    const { container } = render(<OpenProjectMenu path={null} />)
    expect(container).toBeEmptyDOMElement()
  })
})