File size: 5,973 Bytes
766d85d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { render, screen, fireEvent } from '../../../tests/helpers/render'
import { resetAllStores, seedStore } from '../../../tests/helpers/store'
import { buildUser } from '../../../tests/helpers/factories'
import { useAuthStore } from '../../store/authStore'

vi.mock('./CollabChat', () => ({ default: () => <div data-testid="collab-chat">Chat</div> }))
vi.mock('./CollabNotes', () => ({ default: () => <div data-testid="collab-notes">Notes</div> }))
vi.mock('./CollabPolls', () => ({ default: () => <div data-testid="collab-polls">Polls</div> }))
vi.mock('./WhatsNextWidget', () => ({ default: () => <div data-testid="whats-next">WhatsNext</div> }))
vi.mock('../../api/websocket', () => ({
  connect: vi.fn(),
  disconnect: vi.fn(),
  getSocketId: vi.fn(() => null),
  setRefetchCallback: vi.fn(),
  setPreReconnectHook: vi.fn(),
  addListener: vi.fn(),
  removeListener: vi.fn(),
}))

import CollabPanel from './CollabPanel'

let originalInnerWidth: number

function setViewport(width: number) {
  Object.defineProperty(window, 'innerWidth', { value: width, writable: true, configurable: true })
  window.dispatchEvent(new Event('resize'))
}

describe('CollabPanel', () => {
  beforeEach(() => {
    originalInnerWidth = window.innerWidth
    resetAllStores()
    seedStore(useAuthStore, { user: buildUser() })
  })

  afterEach(() => {
    Object.defineProperty(window, 'innerWidth', { value: originalInnerWidth, writable: true, configurable: true })
  })

  // FE-COMP-COLLABPANEL-001
  it('desktop layout renders all four panels', () => {
    setViewport(1280)
    render(<CollabPanel tripId={1} />)
    expect(screen.getByTestId('collab-chat')).toBeInTheDocument()
    expect(screen.getByTestId('collab-notes')).toBeInTheDocument()
    expect(screen.getByTestId('collab-polls')).toBeInTheDocument()
    expect(screen.getByTestId('whats-next')).toBeInTheDocument()
  })

  // FE-COMP-COLLABPANEL-002
  it('mobile layout renders tab bar, not all panels at once', () => {
    setViewport(375)
    render(<CollabPanel tripId={1} />)
    // Tab buttons exist
    expect(screen.getByRole('button', { name: /chat/i })).toBeInTheDocument()
    expect(screen.getByRole('button', { name: /notes/i })).toBeInTheDocument()
    expect(screen.getByRole('button', { name: /polls/i })).toBeInTheDocument()
    expect(screen.getByRole('button', { name: /what.?s next/i })).toBeInTheDocument()
    // Only chat visible by default
    expect(screen.getByTestId('collab-chat')).toBeInTheDocument()
    expect(screen.queryByTestId('collab-notes')).not.toBeInTheDocument()
    expect(screen.queryByTestId('collab-polls')).not.toBeInTheDocument()
    expect(screen.queryByTestId('whats-next')).not.toBeInTheDocument()
  })

  // FE-COMP-COLLABPANEL-003
  it('mobile: clicking Notes tab switches to CollabNotes', () => {
    setViewport(375)
    render(<CollabPanel tripId={1} />)
    fireEvent.click(screen.getByRole('button', { name: /notes/i }))
    expect(screen.getByTestId('collab-notes')).toBeInTheDocument()
    expect(screen.queryByTestId('collab-chat')).not.toBeInTheDocument()
  })

  // FE-COMP-COLLABPANEL-004
  it('mobile: clicking Polls tab switches to CollabPolls', () => {
    setViewport(375)
    render(<CollabPanel tripId={1} />)
    fireEvent.click(screen.getByRole('button', { name: /polls/i }))
    expect(screen.getByTestId('collab-polls')).toBeInTheDocument()
    expect(screen.queryByTestId('collab-chat')).not.toBeInTheDocument()
  })

  // FE-COMP-COLLABPANEL-005
  it('mobile: clicking What\'s Next tab shows WhatsNextWidget', () => {
    setViewport(375)
    render(<CollabPanel tripId={1} />)
    fireEvent.click(screen.getByRole('button', { name: /what.?s next/i }))
    expect(screen.getByTestId('whats-next')).toBeInTheDocument()
    expect(screen.queryByTestId('collab-chat')).not.toBeInTheDocument()
  })

  // FE-COMP-COLLABPANEL-006
  it('mobile: active tab button has accent background style', () => {
    setViewport(375)
    render(<CollabPanel tripId={1} />)
    const chatButton = screen.getByRole('button', { name: /chat/i })
    expect(chatButton.style.background).toBe('var(--accent)')
    const notesButton = screen.getByRole('button', { name: /notes/i })
    expect(notesButton.style.background).toBe('transparent')
  })

  // FE-COMP-COLLABPANEL-007
  it('mobile: default active tab is Chat', () => {
    setViewport(375)
    render(<CollabPanel tripId={1} />)
    expect(screen.getByTestId('collab-chat')).toBeInTheDocument()
  })

  // FE-COMP-COLLABPANEL-008
  it('tripMembers prop is forwarded to WhatsNextWidget', () => {
    setViewport(1280)
    render(<CollabPanel tripId={1} tripMembers={[{ id: 5, username: 'alice', avatar_url: null }]} />)
    expect(screen.getByTestId('whats-next')).toBeInTheDocument()
  })

  // FE-COMP-COLLABPANEL-009
  it('tripId prop is forwarded to child components', () => {
    setViewport(1280)
    render(<CollabPanel tripId={1} />)
    // All children render without errors, confirming props were forwarded
    expect(screen.getByTestId('collab-chat')).toBeInTheDocument()
    expect(screen.getByTestId('collab-notes')).toBeInTheDocument()
    expect(screen.getByTestId('collab-polls')).toBeInTheDocument()
  })

  // FE-COMP-COLLABPANEL-010
  it('resize from desktop to mobile hides side-by-side layout', () => {
    setViewport(1280)
    const { rerender } = render(<CollabPanel tripId={1} />)
    // All four panels visible on desktop
    expect(screen.getByTestId('collab-chat')).toBeInTheDocument()
    expect(screen.getByTestId('collab-notes')).toBeInTheDocument()

    // Switch to mobile
    setViewport(375)
    rerender(<CollabPanel tripId={1} />)

    // Tab bar appears, only chat visible
    expect(screen.getByRole('button', { name: /chat/i })).toBeInTheDocument()
    expect(screen.getByTestId('collab-chat')).toBeInTheDocument()
    expect(screen.queryByTestId('collab-notes')).not.toBeInTheDocument()
  })
})