@linktr.ee/messaging-react 4.2.0-rc-1787083791 → 4.2.0-rc-1787181113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Card-B4lMv-0o.js → Card-BOudQBd6.js} +2 -2
- package/dist/{Card-B4lMv-0o.js.map → Card-BOudQBd6.js.map} +1 -1
- package/dist/{Card-DWL5I62S.cjs → Card-k2959zNX.cjs} +2 -2
- package/dist/{Card-DWL5I62S.cjs.map → Card-k2959zNX.cjs.map} +1 -1
- package/dist/assets/index.css +1 -1
- package/dist/{index-C93LTGLc.js → index-6RdyZh6F.js} +1809 -1912
- package/dist/index-6RdyZh6F.js.map +1 -0
- package/dist/index-BcU18EjV.cjs +3 -0
- package/dist/index-BcU18EjV.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +78 -59
- package/dist/index.js +30 -26
- package/dist/testing.cjs +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +2 -2
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
- package/src/components/AttachmentCard/MediaPlayer.test.tsx +346 -0
- package/src/components/AttachmentCard/Thumbnail.test.tsx +215 -0
- package/src/components/AttachmentCard/index.test.tsx +160 -0
- package/src/components/Avatar/Avatar.test.tsx +126 -0
- package/src/components/Avatar/getAvatarEmoji.test.ts +39 -0
- package/src/components/ChannelList/ChannelListContext.test.tsx +87 -0
- package/src/components/ChannelList/CustomChannelPreview.test.tsx +410 -3
- package/src/components/ChannelList/index.test.tsx +132 -1
- package/src/components/CustomMessage/CustomMessage.stories.tsx +6 -314
- package/src/components/CustomMessage/CustomMessage.test.tsx +56 -2
- package/src/components/CustomMessage/Locked.stories.tsx +108 -0
- package/src/components/CustomMessage/MessageTag.stories.tsx +17 -53
- package/src/components/CustomMessage/MessageTag.test.tsx +7 -40
- package/src/components/CustomMessage/MessageTag.tsx +7 -39
- package/src/components/CustomMessage/PaidMessage.stories.tsx +42 -0
- package/src/components/CustomMessage/SentMessageDeliveryStatus.test.tsx +8 -7
- package/src/components/CustomMessage/SentMessageDeliveryStatus.tsx +2 -1
- package/src/components/CustomMessage/StreamAttachmentMessage.test.tsx +0 -33
- package/src/components/CustomMessage/StreamAttachmentMessage.tsx +0 -6
- package/src/components/CustomMessage/Tip.stories.tsx +48 -0
- package/src/components/CustomMessage/TipMessage/TipMessage.stories.tsx +51 -0
- package/src/components/CustomMessage/TipMessage/TipMessage.test.tsx +65 -0
- package/src/components/CustomMessage/TipMessage/index.tsx +27 -0
- package/src/components/CustomMessage/index.tsx +22 -19
- package/src/components/FaqList/FaqList.test.tsx +204 -0
- package/src/components/LinkAttachment/LinkAttachment.test.tsx +327 -0
- package/src/components/LinkAttachment/components/_shared/BubbleTail.test.tsx +76 -0
- package/src/components/LinkAttachment/components/_shared/CardBody.test.tsx +248 -0
- package/src/components/LinkAttachment/components/_shared/CardCta.test.tsx +123 -0
- package/src/components/LinkAttachment/components/_shared/CardShell.test.tsx +193 -0
- package/src/components/LinkAttachment/components/_shared/CardThumbnail.test.tsx +242 -0
- package/src/components/LinkAttachment/components/_shared/hex.test.ts +37 -0
- package/src/components/LinkAttachment/components/_shared/normalizeExternalHref.test.ts +72 -0
- package/src/components/LinkAttachment/components/_shared/useChinPalette.test.ts +162 -0
- package/src/components/MessageAttachment/Audio/AudioAttachment.stories.tsx +58 -165
- package/src/components/MessageAttachment/Audio/index.tsx +77 -71
- package/src/components/MessageAttachment/MessageAttachment.test.tsx +74 -176
- package/src/components/MessageAttachment/index.tsx +9 -25
- package/src/components/MessageAttachment/types.ts +9 -19
- package/src/components/MessagingShell/MessagingShell.test.tsx +20 -0
- package/src/components/MessagingShell/index.tsx +2 -0
- package/src/index.ts +4 -0
- package/src/logging/index.test.tsx +136 -0
- package/src/logging/index.tsx +48 -0
- package/src/providers/MessagingProvider.test.tsx +113 -1
- package/src/providers/MessagingProvider.tsx +25 -15
- package/src/stories/customMessageStoryTemplate.tsx +199 -0
- package/src/styles.css +10 -121
- package/src/testing/createMockMessagingClient.ts +2 -2
- package/src/types.ts +9 -0
- package/dist/index-B-9LkWep.cjs +0 -3
- package/dist/index-B-9LkWep.cjs.map +0 -1
- package/dist/index-C93LTGLc.js.map +0 -1
- package/src/components/MessageAttachment/Audio/WaveformAudioRow.tsx +0 -335
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { renderWithProviders, screen } from '../../test/utils'
|
|
5
|
+
|
|
6
|
+
import AttachmentCard from './index'
|
|
7
|
+
|
|
8
|
+
const thumbnail = <div data-testid="thumbnail">thumbnail</div>
|
|
9
|
+
|
|
10
|
+
describe('AttachmentCard', () => {
|
|
11
|
+
it('applies the dark and light root surfaces and type icon colors', () => {
|
|
12
|
+
const dark = renderWithProviders(
|
|
13
|
+
<AttachmentCard
|
|
14
|
+
variant="dark"
|
|
15
|
+
thumbnail={thumbnail}
|
|
16
|
+
mimeType="application/pdf"
|
|
17
|
+
title="Dark file"
|
|
18
|
+
/>
|
|
19
|
+
)
|
|
20
|
+
expect(screen.getByText('Dark file')).toBeInTheDocument()
|
|
21
|
+
expect(dark.container.firstElementChild).toHaveClass('bg-[#1e2330]')
|
|
22
|
+
expect(dark.container.querySelector('svg')).toHaveClass('text-white/55')
|
|
23
|
+
dark.unmount()
|
|
24
|
+
|
|
25
|
+
const light = renderWithProviders(
|
|
26
|
+
<AttachmentCard
|
|
27
|
+
variant="light"
|
|
28
|
+
thumbnail={thumbnail}
|
|
29
|
+
mimeType="application/pdf"
|
|
30
|
+
title="Light file"
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
expect(light.container.firstElementChild).toHaveClass('bg-white')
|
|
34
|
+
expect(light.container.querySelector('svg')).toHaveClass('text-black/55')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('uses the dark placeholder title and dims it when title is absent', () => {
|
|
38
|
+
renderWithProviders(
|
|
39
|
+
<AttachmentCard
|
|
40
|
+
variant="dark"
|
|
41
|
+
thumbnail={thumbnail}
|
|
42
|
+
mimeType="application/pdf"
|
|
43
|
+
placeholderTitle="Waiting for title"
|
|
44
|
+
/>
|
|
45
|
+
)
|
|
46
|
+
expect(screen.getByText('Waiting for title')).toHaveClass('text-white/30')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('does not render a light title for missing or whitespace-only values', () => {
|
|
50
|
+
const { rerender } = renderWithProviders(
|
|
51
|
+
<AttachmentCard
|
|
52
|
+
variant="light"
|
|
53
|
+
thumbnail={thumbnail}
|
|
54
|
+
mimeType="application/pdf"
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
expect(screen.queryByText('Attachment title')).toBeNull()
|
|
58
|
+
|
|
59
|
+
rerender(
|
|
60
|
+
<AttachmentCard
|
|
61
|
+
variant="light"
|
|
62
|
+
thumbnail={thumbnail}
|
|
63
|
+
mimeType="application/pdf"
|
|
64
|
+
title=" "
|
|
65
|
+
/>
|
|
66
|
+
)
|
|
67
|
+
expect(screen.queryByText(' ')).toBeNull()
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('uses an undimmed title class when a dark title is provided', () => {
|
|
71
|
+
renderWithProviders(
|
|
72
|
+
<AttachmentCard
|
|
73
|
+
variant="dark"
|
|
74
|
+
thumbnail={thumbnail}
|
|
75
|
+
mimeType="application/pdf"
|
|
76
|
+
title="Named file"
|
|
77
|
+
/>
|
|
78
|
+
)
|
|
79
|
+
expect(screen.getByText('Named file')).toHaveClass('text-white')
|
|
80
|
+
expect(screen.getByText('Named file')).not.toHaveClass('text-white/30')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('renders detail only for non-empty values', () => {
|
|
84
|
+
const { rerender } = renderWithProviders(
|
|
85
|
+
<AttachmentCard
|
|
86
|
+
variant="light"
|
|
87
|
+
thumbnail={thumbnail}
|
|
88
|
+
mimeType="application/pdf"
|
|
89
|
+
title="File"
|
|
90
|
+
detail="2 MB"
|
|
91
|
+
/>
|
|
92
|
+
)
|
|
93
|
+
expect(screen.getByText('2 MB')).toBeInTheDocument()
|
|
94
|
+
|
|
95
|
+
rerender(
|
|
96
|
+
<AttachmentCard
|
|
97
|
+
variant="light"
|
|
98
|
+
thumbnail={thumbnail}
|
|
99
|
+
mimeType="application/pdf"
|
|
100
|
+
title="File"
|
|
101
|
+
detail=""
|
|
102
|
+
/>
|
|
103
|
+
)
|
|
104
|
+
expect(screen.queryByText('2 MB')).toBeNull()
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('renders optional slots only when supplied', () => {
|
|
108
|
+
const { container } = renderWithProviders(
|
|
109
|
+
<AttachmentCard
|
|
110
|
+
variant="light"
|
|
111
|
+
thumbnail={thumbnail}
|
|
112
|
+
mimeType="application/pdf"
|
|
113
|
+
statusBadge={<span>Ready</span>}
|
|
114
|
+
action={<button type="button">Open</button>}
|
|
115
|
+
topLeft={<span>Left</span>}
|
|
116
|
+
topRight={<span>Right</span>}
|
|
117
|
+
/>
|
|
118
|
+
)
|
|
119
|
+
expect(screen.getByText('Ready')).toBeInTheDocument()
|
|
120
|
+
expect(screen.getByRole('button', { name: 'Open' })).toBeInTheDocument()
|
|
121
|
+
expect(screen.getByText('Left').parentElement).toHaveClass(
|
|
122
|
+
'pointer-events-auto',
|
|
123
|
+
'absolute',
|
|
124
|
+
'left-3',
|
|
125
|
+
'top-3'
|
|
126
|
+
)
|
|
127
|
+
expect(screen.getByText('Right').parentElement).toHaveClass(
|
|
128
|
+
'pointer-events-auto',
|
|
129
|
+
'absolute',
|
|
130
|
+
'right-3',
|
|
131
|
+
'top-3'
|
|
132
|
+
)
|
|
133
|
+
expect(container.querySelectorAll('.pointer-events-auto')).toHaveLength(2)
|
|
134
|
+
|
|
135
|
+
const withoutSlots = renderWithProviders(
|
|
136
|
+
<AttachmentCard
|
|
137
|
+
variant="light"
|
|
138
|
+
thumbnail={thumbnail}
|
|
139
|
+
mimeType="application/pdf"
|
|
140
|
+
/>
|
|
141
|
+
)
|
|
142
|
+
expect(
|
|
143
|
+
withoutSlots.container.querySelectorAll('.pointer-events-auto')
|
|
144
|
+
).toHaveLength(0)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('forwards rootRef and data-testid to the root', () => {
|
|
148
|
+
const rootRef = React.createRef<HTMLDivElement>()
|
|
149
|
+
renderWithProviders(
|
|
150
|
+
<AttachmentCard
|
|
151
|
+
variant="light"
|
|
152
|
+
thumbnail={thumbnail}
|
|
153
|
+
mimeType="application/pdf"
|
|
154
|
+
rootRef={rootRef}
|
|
155
|
+
data-testid="attachment-card"
|
|
156
|
+
/>
|
|
157
|
+
)
|
|
158
|
+
expect(screen.getByTestId('attachment-card')).toBe(rootRef.current)
|
|
159
|
+
})
|
|
160
|
+
})
|
|
@@ -27,4 +27,130 @@ describe('Avatar', () => {
|
|
|
27
27
|
it('keeps fixed emoji sizes for larger avatars', () => {
|
|
28
28
|
expect(emojiFontSize(40)).toHaveStyle({ fontSize: '14px' })
|
|
29
29
|
})
|
|
30
|
+
|
|
31
|
+
it.each([
|
|
32
|
+
[32, '14px'],
|
|
33
|
+
[55, '14px'],
|
|
34
|
+
[56, '18px'],
|
|
35
|
+
[119, '18px'],
|
|
36
|
+
[120, '36px'],
|
|
37
|
+
])(
|
|
38
|
+
'uses the exact fixed font size at the %spx boundary',
|
|
39
|
+
(size, fontSize) => {
|
|
40
|
+
expect(emojiFontSize(size)).toHaveStyle({ fontSize })
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
it('does not show a star by default but shows one when starred', () => {
|
|
45
|
+
const defaultAvatar = renderWithProviders(
|
|
46
|
+
<Avatar id="user-1" name="Alice" />
|
|
47
|
+
)
|
|
48
|
+
expect(defaultAvatar.container.querySelector('svg')).not.toBeInTheDocument()
|
|
49
|
+
|
|
50
|
+
const starredAvatar = renderWithProviders(
|
|
51
|
+
<Avatar id="user-1" name="Alice" starred />
|
|
52
|
+
)
|
|
53
|
+
expect(starredAvatar.container.querySelector('svg')).toBeInTheDocument()
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('uses a squircle by default and a circle when explicitly requested', () => {
|
|
57
|
+
const squircleAvatar = renderWithProviders(
|
|
58
|
+
<Avatar id="user-1" name="Alice" />
|
|
59
|
+
)
|
|
60
|
+
const squircleElements = squircleAvatar.container.querySelectorAll(
|
|
61
|
+
'[style*="border-radius"]'
|
|
62
|
+
)
|
|
63
|
+
expect(squircleElements).toHaveLength(3)
|
|
64
|
+
squircleElements.forEach((element) =>
|
|
65
|
+
expect(element).toHaveStyle({ borderRadius: '1rem' })
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
const circleAvatar = renderWithProviders(
|
|
69
|
+
<Avatar id="user-1" name="Alice" shape="circle" />
|
|
70
|
+
)
|
|
71
|
+
const circleElements = circleAvatar.container.querySelectorAll(
|
|
72
|
+
'[style*="border-radius"]'
|
|
73
|
+
)
|
|
74
|
+
expect(circleElements).toHaveLength(3)
|
|
75
|
+
circleElements.forEach((element) =>
|
|
76
|
+
expect(element).toHaveStyle({ borderRadius: '50%' })
|
|
77
|
+
)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('only applies the AI ring when dmAgentEnabled is true', () => {
|
|
81
|
+
const defaultAvatar = renderWithProviders(
|
|
82
|
+
<Avatar id="user-1" name="Alice" size={40} />
|
|
83
|
+
)
|
|
84
|
+
expect(
|
|
85
|
+
defaultAvatar.container.querySelector('[data-testid="avatar-ring"]')
|
|
86
|
+
).not.toHaveStyle({
|
|
87
|
+
borderWidth: '2px',
|
|
88
|
+
borderStyle: 'solid',
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
const enabledAvatar = renderWithProviders(
|
|
92
|
+
<Avatar id="user-1" name="Alice" size={40} dmAgentEnabled />
|
|
93
|
+
)
|
|
94
|
+
expect(
|
|
95
|
+
enabledAvatar.container.querySelector('[data-testid="avatar-ring"]')
|
|
96
|
+
).toHaveStyle({
|
|
97
|
+
borderWidth: '2px',
|
|
98
|
+
borderStyle: 'solid',
|
|
99
|
+
borderColor: 'var(--AI-Gradient, #7F22FE)',
|
|
100
|
+
boxShadow: 'inset 0 1px 2px 0 rgba(255, 255, 255, 0.5)',
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const smallEnabledAvatar = renderWithProviders(
|
|
104
|
+
<Avatar id="user-1" name="Alice" size={20} dmAgentEnabled />
|
|
105
|
+
)
|
|
106
|
+
expect(
|
|
107
|
+
smallEnabledAvatar.container.querySelector('[data-testid="avatar-ring"]')
|
|
108
|
+
).toHaveStyle({ borderWidth: '1px' })
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('renders an image instead of the emoji fallback when image is provided', () => {
|
|
112
|
+
const fallbackAvatar = renderWithProviders(<Avatar id="" name="Alice" />)
|
|
113
|
+
expect(
|
|
114
|
+
fallbackAvatar.container.querySelector('img')
|
|
115
|
+
).not.toBeInTheDocument()
|
|
116
|
+
expect(fallbackAvatar.container).toHaveTextContent('🍎')
|
|
117
|
+
expect(
|
|
118
|
+
fallbackAvatar.container.querySelector('.avatar-fallback')
|
|
119
|
+
).toHaveClass(
|
|
120
|
+
'avatar-fallback',
|
|
121
|
+
'flex',
|
|
122
|
+
'h-full',
|
|
123
|
+
'w-full',
|
|
124
|
+
'items-center',
|
|
125
|
+
'justify-center',
|
|
126
|
+
'font-semibold',
|
|
127
|
+
'select-none',
|
|
128
|
+
'transition-colors'
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
const imageAvatar = renderWithProviders(
|
|
132
|
+
<Avatar id="" name="Alice" image="https://example.com/avatar.png" />
|
|
133
|
+
)
|
|
134
|
+
expect(imageAvatar.container.querySelector('img')).toHaveAttribute(
|
|
135
|
+
'src',
|
|
136
|
+
'https://example.com/avatar.png'
|
|
137
|
+
)
|
|
138
|
+
expect(imageAvatar.container).not.toHaveTextContent('🍎')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('applies the fallback background color and forwards custom classes', () => {
|
|
142
|
+
const { container } = renderWithProviders(
|
|
143
|
+
<Avatar id="" name="Alice" className="custom-avatar" />
|
|
144
|
+
)
|
|
145
|
+
const root = container.firstElementChild
|
|
146
|
+
const ring = container.querySelector('[data-testid="avatar-ring"]')
|
|
147
|
+
|
|
148
|
+
expect(root).toHaveClass('relative', 'flex-shrink-0', 'custom-avatar')
|
|
149
|
+
expect(ring).toHaveClass('h-full', 'w-full', 'bg-transparent')
|
|
150
|
+
expect(root).toHaveStyle({
|
|
151
|
+
backgroundColor: '#FFD1DD',
|
|
152
|
+
width: '40px',
|
|
153
|
+
height: '40px',
|
|
154
|
+
})
|
|
155
|
+
})
|
|
30
156
|
})
|
|
@@ -29,4 +29,43 @@ describe('getAvatarBgColor', () => {
|
|
|
29
29
|
expect(color).toBe(emojiBgColors[emoji])
|
|
30
30
|
expect(getAvatarBgColor(id)).toBe(color)
|
|
31
31
|
})
|
|
32
|
+
|
|
33
|
+
it.each([
|
|
34
|
+
['', '🍎', '#FFD1DD'],
|
|
35
|
+
['id-2', '🍌', '#FFF1C9'],
|
|
36
|
+
['id-3', '🍇', '#E6D9FF'],
|
|
37
|
+
['id-4', '🍊', '#D6F4FF'],
|
|
38
|
+
['id-5', '🍓', '#FFE0AE'],
|
|
39
|
+
['id-6', '🥥', '#F7E7D8'],
|
|
40
|
+
['id-7', '🍒', '#DFF4D8'],
|
|
41
|
+
['id-8', '🥭', '#FFD8C2'],
|
|
42
|
+
['id-9', '🍉', '#D6EBFF'],
|
|
43
|
+
['id-10', '🍋', '#CAEEB5'],
|
|
44
|
+
['id-11', '🥝', '#FFE7C7'],
|
|
45
|
+
['id-12', '🫒', '#F6E3B4'],
|
|
46
|
+
['id-13', '🍈', '#D9F7E1'],
|
|
47
|
+
])('returns the exact fruit pair for %j', (id, emoji, bgColor) => {
|
|
48
|
+
expect(getAvatarEmoji(id)).toBe(emoji)
|
|
49
|
+
expect(getAvatarBgColor(id)).toBe(bgColor)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('uses the absolute hash value for ids with a negative raw hash', () => {
|
|
53
|
+
const id = 'id-100'
|
|
54
|
+
|
|
55
|
+
expect(getAvatarEmoji(id)).toBe('🥭')
|
|
56
|
+
expect(getAvatarBgColor(id)).toBe('#FFD8C2')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('is deterministic and keeps emoji and background color paired', () => {
|
|
60
|
+
const ids = ['', 'id-2', 'id-7', 'id-13', 'id-100']
|
|
61
|
+
|
|
62
|
+
ids.forEach((id) => {
|
|
63
|
+
const emoji = getAvatarEmoji(id)
|
|
64
|
+
const color = getAvatarBgColor(id)
|
|
65
|
+
|
|
66
|
+
expect(getAvatarEmoji(id)).toBe(emoji)
|
|
67
|
+
expect(getAvatarBgColor(id)).toBe(color)
|
|
68
|
+
expect(emojiBgColors[emoji]).toBe(color)
|
|
69
|
+
})
|
|
70
|
+
})
|
|
32
71
|
})
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Channel } from 'stream-chat'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { fireEvent, renderWithProviders, screen } from '../../test/utils'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
ChannelListProvider,
|
|
8
|
+
useChannelListContext,
|
|
9
|
+
} from './ChannelListContext'
|
|
10
|
+
|
|
11
|
+
const channel = { id: 'channel-1' } as Channel
|
|
12
|
+
|
|
13
|
+
function ContextConsumer() {
|
|
14
|
+
const value = useChannelListContext()
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div>
|
|
18
|
+
<span data-testid="selected-channel">
|
|
19
|
+
{value.selectedChannel?.id ?? 'undefined'}
|
|
20
|
+
</span>
|
|
21
|
+
<span data-testid="debug">{String(value.debug)}</span>
|
|
22
|
+
<span data-testid="render-message-preview">
|
|
23
|
+
{value.renderMessagePreview ? 'provided' : 'undefined'}
|
|
24
|
+
</span>
|
|
25
|
+
<span data-testid="channel-preview">
|
|
26
|
+
{value.channelPreview ? 'provided' : 'undefined'}
|
|
27
|
+
</span>
|
|
28
|
+
<span data-testid="viewer-language">
|
|
29
|
+
{value.viewerLanguage ?? 'undefined'}
|
|
30
|
+
</span>
|
|
31
|
+
<button type="button" onClick={() => value.onChannelSelect(channel)}>
|
|
32
|
+
Select channel
|
|
33
|
+
</button>
|
|
34
|
+
</div>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe('ChannelListContext', () => {
|
|
39
|
+
it('provides safe documented defaults without a provider', () => {
|
|
40
|
+
renderWithProviders(<ContextConsumer />)
|
|
41
|
+
|
|
42
|
+
expect(screen.getByTestId('selected-channel')).toHaveTextContent(
|
|
43
|
+
'undefined'
|
|
44
|
+
)
|
|
45
|
+
expect(screen.getByTestId('debug')).toHaveTextContent('false')
|
|
46
|
+
expect(screen.getByTestId('render-message-preview')).toHaveTextContent(
|
|
47
|
+
'undefined'
|
|
48
|
+
)
|
|
49
|
+
expect(screen.getByTestId('channel-preview')).toHaveTextContent('undefined')
|
|
50
|
+
expect(screen.getByTestId('viewer-language')).toHaveTextContent('undefined')
|
|
51
|
+
expect(() => fireEvent.click(screen.getByRole('button'))).not.toThrow()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('exposes the value supplied by a provider', () => {
|
|
55
|
+
const onChannelSelect = vi.fn()
|
|
56
|
+
const ChannelPreview = () => null
|
|
57
|
+
const renderMessagePreview = () => 'preview'
|
|
58
|
+
|
|
59
|
+
renderWithProviders(
|
|
60
|
+
<ChannelListProvider
|
|
61
|
+
value={{
|
|
62
|
+
selectedChannel: channel,
|
|
63
|
+
onChannelSelect,
|
|
64
|
+
debug: true,
|
|
65
|
+
renderMessagePreview,
|
|
66
|
+
channelPreview: ChannelPreview,
|
|
67
|
+
viewerLanguage: 'es',
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
<ContextConsumer />
|
|
71
|
+
</ChannelListProvider>
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
expect(screen.getByTestId('selected-channel')).toHaveTextContent(
|
|
75
|
+
'channel-1'
|
|
76
|
+
)
|
|
77
|
+
expect(screen.getByTestId('debug')).toHaveTextContent('true')
|
|
78
|
+
expect(screen.getByTestId('render-message-preview')).toHaveTextContent(
|
|
79
|
+
'provided'
|
|
80
|
+
)
|
|
81
|
+
expect(screen.getByTestId('channel-preview')).toHaveTextContent('provided')
|
|
82
|
+
expect(screen.getByTestId('viewer-language')).toHaveTextContent('es')
|
|
83
|
+
|
|
84
|
+
fireEvent.click(screen.getByRole('button'))
|
|
85
|
+
expect(onChannelSelect).toHaveBeenCalledWith(channel)
|
|
86
|
+
})
|
|
87
|
+
})
|