@linktr.ee/messaging-react 1.32.1 → 1.33.0-rc-1777504230
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-ClE_iExA.js → Card-BsqYzZt1.js} +55 -55
- package/dist/Card-BsqYzZt1.js.map +1 -0
- package/dist/{Card-1CQEn-OT.js → Card-Cnn9V-W7.js} +44 -44
- package/dist/Card-Cnn9V-W7.js.map +1 -0
- package/dist/assets/index.css +1 -1
- package/dist/index-BMfupE8K.js +3130 -0
- package/dist/index-BMfupE8K.js.map +1 -0
- package/dist/index.d.ts +19 -1
- package/dist/index.js +20 -2477
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ChannelInfoDialog/index.tsx +3 -1
- package/src/components/ChannelView.stories.tsx +38 -0
- package/src/components/ChannelView.test.tsx +25 -6
- package/src/components/ChannelView.tsx +26 -6
- package/src/components/CustomMessageInput/CustomMessageInput.stories.tsx +180 -0
- package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +63 -1
- package/src/components/CustomMessageInput/index.tsx +24 -5
- package/src/components/LockedAttachment/components/Creator/Card.tsx +11 -11
- package/src/components/LockedAttachment/components/MediaPlayer.tsx +10 -1
- package/src/components/LockedAttachment/components/Visitor/Card.tsx +9 -9
- package/src/components/LockedAttachment/components/Visitor/CardActions.tsx +2 -2
- package/src/components/MediaMessage/MediaMessage.stories.tsx +233 -0
- package/src/components/MediaMessage/MediaMessage.test.tsx +520 -0
- package/src/components/MediaMessage/index.tsx +476 -0
- package/src/components/MessagingShell/index.tsx +2 -0
- package/src/index.ts +2 -0
- package/src/styles.css +49 -0
- package/src/types.ts +13 -0
- package/dist/Card-1CQEn-OT.js.map +0 -1
- package/dist/Card-ClE_iExA.js.map +0 -1
- package/dist/MediaPlayer-B9Ws2NeE.js +0 -292
- package/dist/MediaPlayer-B9Ws2NeE.js.map +0 -1
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import type { LocalMessage } from 'stream-chat'
|
|
3
|
+
import { beforeAll, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
|
|
5
|
+
import { renderWithProviders, screen, fireEvent } from '../../test/utils'
|
|
6
|
+
|
|
7
|
+
import { MediaMessage } from '.'
|
|
8
|
+
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
HTMLDialogElement.prototype.showModal = vi.fn(function (this: HTMLDialogElement) {
|
|
11
|
+
this.setAttribute('open', '')
|
|
12
|
+
})
|
|
13
|
+
HTMLDialogElement.prototype.close = vi.fn(function (this: HTMLDialogElement) {
|
|
14
|
+
this.removeAttribute('open')
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
vi.mock('../Avatar', () => ({
|
|
19
|
+
Avatar: ({ id }: { id: string }) => (
|
|
20
|
+
<div data-testid="avatar" data-user-id={id} />
|
|
21
|
+
),
|
|
22
|
+
}))
|
|
23
|
+
|
|
24
|
+
vi.mock('../LockedAttachment/components/MediaPlayer', () => ({
|
|
25
|
+
default: ({
|
|
26
|
+
source,
|
|
27
|
+
mimeType,
|
|
28
|
+
onContainerClick,
|
|
29
|
+
}: {
|
|
30
|
+
source: string
|
|
31
|
+
mimeType: string
|
|
32
|
+
onContainerClick?: (e: React.MouseEvent) => void
|
|
33
|
+
}) => (
|
|
34
|
+
<div
|
|
35
|
+
role="button"
|
|
36
|
+
tabIndex={0}
|
|
37
|
+
data-testid="media-player"
|
|
38
|
+
data-source={source}
|
|
39
|
+
data-mime-type={mimeType}
|
|
40
|
+
onClick={onContainerClick}
|
|
41
|
+
onKeyDown={undefined}
|
|
42
|
+
/>
|
|
43
|
+
),
|
|
44
|
+
}))
|
|
45
|
+
|
|
46
|
+
vi.mock('../LockedAttachment/utils/icons', () => ({
|
|
47
|
+
renderTypeIcon: () => <span data-testid="type-icon" />,
|
|
48
|
+
}))
|
|
49
|
+
|
|
50
|
+
vi.mock('../LockedAttachment/utils/mimeType', () => ({
|
|
51
|
+
getSourceType: (mimeType: string) => {
|
|
52
|
+
if (mimeType.startsWith('video/')) return 'video'
|
|
53
|
+
if (mimeType.startsWith('image/')) return 'image'
|
|
54
|
+
if (mimeType.startsWith('audio/')) return 'audio'
|
|
55
|
+
return 'document'
|
|
56
|
+
},
|
|
57
|
+
}))
|
|
58
|
+
|
|
59
|
+
const msg = (overrides: Record<string, unknown> = {}): LocalMessage =>
|
|
60
|
+
({
|
|
61
|
+
id: 'msg-1',
|
|
62
|
+
text: '',
|
|
63
|
+
type: 'regular',
|
|
64
|
+
created_at: new Date(),
|
|
65
|
+
updated_at: new Date(),
|
|
66
|
+
deleted_at: null,
|
|
67
|
+
pinned_at: null,
|
|
68
|
+
status: 'received',
|
|
69
|
+
user: { id: 'user-1', name: 'Alice' },
|
|
70
|
+
attachments: [],
|
|
71
|
+
...overrides,
|
|
72
|
+
}) as unknown as LocalMessage
|
|
73
|
+
|
|
74
|
+
describe('MediaMessage', () => {
|
|
75
|
+
it('renders nothing when no media URL is resolvable', () => {
|
|
76
|
+
const { container } = renderWithProviders(<MediaMessage message={msg()} />)
|
|
77
|
+
expect(container.firstChild).toBeNull()
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('renders MediaPlayer immediately for a video attachment', () => {
|
|
81
|
+
renderWithProviders(
|
|
82
|
+
<MediaMessage
|
|
83
|
+
message={msg({
|
|
84
|
+
attachments: [
|
|
85
|
+
{
|
|
86
|
+
type: 'video',
|
|
87
|
+
asset_url: 'https://cdn.example.com/clip.mp4',
|
|
88
|
+
mime_type: 'video/mp4',
|
|
89
|
+
title: 'My Clip',
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
})}
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
const player = screen.getByTestId('media-player')
|
|
97
|
+
expect(player).toBeInTheDocument()
|
|
98
|
+
expect(player).toHaveAttribute('data-source', 'https://cdn.example.com/clip.mp4')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('opens viewer when the video player container is clicked', () => {
|
|
102
|
+
renderWithProviders(
|
|
103
|
+
<MediaMessage
|
|
104
|
+
message={msg({
|
|
105
|
+
attachments: [
|
|
106
|
+
{
|
|
107
|
+
type: 'video',
|
|
108
|
+
asset_url: 'https://cdn.example.com/clip.mp4',
|
|
109
|
+
mime_type: 'video/mp4',
|
|
110
|
+
title: 'My Clip',
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
})}
|
|
114
|
+
/>
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
fireEvent.click(screen.getByTestId('media-player'))
|
|
118
|
+
expect(HTMLDialogElement.prototype.showModal).toHaveBeenCalled()
|
|
119
|
+
expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument()
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('renders MediaPlayer for an audio attachment', () => {
|
|
123
|
+
renderWithProviders(
|
|
124
|
+
<MediaMessage
|
|
125
|
+
message={msg({
|
|
126
|
+
attachments: [
|
|
127
|
+
{
|
|
128
|
+
type: 'audio',
|
|
129
|
+
asset_url: 'https://cdn.example.com/track.mp3',
|
|
130
|
+
mime_type: 'audio/mpeg',
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
})}
|
|
134
|
+
/>
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
expect(screen.getByTestId('media-player')).toHaveAttribute(
|
|
138
|
+
'data-source',
|
|
139
|
+
'https://cdn.example.com/track.mp3'
|
|
140
|
+
)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('does not show viewer or expand button for audio', () => {
|
|
144
|
+
renderWithProviders(
|
|
145
|
+
<MediaMessage
|
|
146
|
+
message={msg({
|
|
147
|
+
attachments: [
|
|
148
|
+
{
|
|
149
|
+
type: 'audio',
|
|
150
|
+
asset_url: 'https://cdn.example.com/track.mp3',
|
|
151
|
+
mime_type: 'audio/mpeg',
|
|
152
|
+
title: 'My Track',
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
})}
|
|
156
|
+
/>
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
expect(screen.queryByRole('button', { name: 'View full screen' })).not.toBeInTheDocument()
|
|
160
|
+
expect(screen.queryByRole('button', { name: 'Close' })).not.toBeInTheDocument()
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('renders an img for an image attachment and opens viewer on click', () => {
|
|
164
|
+
renderWithProviders(
|
|
165
|
+
<MediaMessage
|
|
166
|
+
message={msg({
|
|
167
|
+
attachments: [
|
|
168
|
+
{
|
|
169
|
+
type: 'image',
|
|
170
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
171
|
+
mime_type: 'image/jpeg',
|
|
172
|
+
title: 'My Photo',
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
})}
|
|
176
|
+
/>
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
const image = screen.getByRole('img', { name: 'My Photo' })
|
|
180
|
+
expect(image).toHaveAttribute('src', 'https://cdn.example.com/photo.jpg')
|
|
181
|
+
|
|
182
|
+
// Clicking the image button opens the viewer
|
|
183
|
+
fireEvent.click(screen.getByRole('button', { name: 'My Photo' }))
|
|
184
|
+
expect(HTMLDialogElement.prototype.showModal).toHaveBeenCalled()
|
|
185
|
+
const viewerImages = screen.getAllByRole('img', { name: 'My Photo' })
|
|
186
|
+
expect(viewerImages.some((img) => img.classList.contains('rounded-2xl'))).toBe(true)
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
it('does not show expand button in chin for images, only download', () => {
|
|
190
|
+
renderWithProviders(
|
|
191
|
+
<MediaMessage
|
|
192
|
+
message={msg({
|
|
193
|
+
attachments: [
|
|
194
|
+
{
|
|
195
|
+
type: 'image',
|
|
196
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
197
|
+
mime_type: 'image/jpeg',
|
|
198
|
+
title: 'My Photo',
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
})}
|
|
202
|
+
/>
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
// Thumbnail button + download button — no separate expand/fullscreen button
|
|
206
|
+
expect(screen.queryByRole('button', { name: 'View full screen' })).not.toBeInTheDocument()
|
|
207
|
+
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('renders PDF card with a viewer button', () => {
|
|
211
|
+
renderWithProviders(
|
|
212
|
+
<MediaMessage
|
|
213
|
+
message={msg({
|
|
214
|
+
attachments: [
|
|
215
|
+
{
|
|
216
|
+
type: 'file',
|
|
217
|
+
asset_url: 'https://cdn.example.com/report.pdf',
|
|
218
|
+
mime_type: 'application/pdf',
|
|
219
|
+
title: 'Annual Report',
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
})}
|
|
223
|
+
/>
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
expect(screen.getByRole('button', { name: 'Open PDF viewer' })).toBeInTheDocument()
|
|
227
|
+
expect(screen.getByText('Annual Report')).toBeInTheDocument()
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('opens PDF viewer when PDF thumbnail is clicked', () => {
|
|
231
|
+
renderWithProviders(
|
|
232
|
+
<MediaMessage
|
|
233
|
+
message={msg({
|
|
234
|
+
attachments: [
|
|
235
|
+
{
|
|
236
|
+
type: 'file',
|
|
237
|
+
asset_url: 'https://cdn.example.com/report.pdf',
|
|
238
|
+
mime_type: 'application/pdf',
|
|
239
|
+
title: 'Annual Report',
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
})}
|
|
243
|
+
/>
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
fireEvent.click(screen.getByRole('button', { name: 'Open PDF viewer' }))
|
|
247
|
+
expect(HTMLDialogElement.prototype.showModal).toHaveBeenCalled()
|
|
248
|
+
expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument()
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it('renders unknown file as a link with no viewer button', () => {
|
|
252
|
+
renderWithProviders(
|
|
253
|
+
<MediaMessage
|
|
254
|
+
message={msg({
|
|
255
|
+
attachments: [
|
|
256
|
+
{
|
|
257
|
+
type: 'file',
|
|
258
|
+
asset_url: 'https://cdn.example.com/data.bin',
|
|
259
|
+
mime_type: 'application/octet-stream',
|
|
260
|
+
title: 'Unknown File',
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
})}
|
|
264
|
+
/>
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
// No viewer button for unknown files
|
|
268
|
+
expect(screen.queryByRole('button', { name: 'Open PDF viewer' })).not.toBeInTheDocument()
|
|
269
|
+
// Thumbnail is a plain link (opens in new tab)
|
|
270
|
+
const links = screen.getAllByRole('link')
|
|
271
|
+
expect(links.some((l) => l.getAttribute('href') === 'https://cdn.example.com/data.bin')).toBe(true)
|
|
272
|
+
expect(screen.getByText('Unknown File')).toBeInTheDocument()
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('shows title and file size in chin', () => {
|
|
276
|
+
renderWithProviders(
|
|
277
|
+
<MediaMessage
|
|
278
|
+
message={msg({
|
|
279
|
+
attachments: [
|
|
280
|
+
{
|
|
281
|
+
type: 'video',
|
|
282
|
+
asset_url: 'https://cdn.example.com/clip.mp4',
|
|
283
|
+
mime_type: 'video/mp4',
|
|
284
|
+
title: 'Clip',
|
|
285
|
+
file_size: 2048,
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
})}
|
|
289
|
+
/>
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
expect(screen.getByText('Clip')).toBeInTheDocument()
|
|
293
|
+
expect(screen.getByText('2.0 KB')).toBeInTheDocument()
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
it('renders Avatar for a message from another user', () => {
|
|
297
|
+
renderWithProviders(
|
|
298
|
+
<MediaMessage
|
|
299
|
+
isMyMessage={false}
|
|
300
|
+
message={msg({
|
|
301
|
+
attachments: [
|
|
302
|
+
{
|
|
303
|
+
type: 'image',
|
|
304
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
305
|
+
mime_type: 'image/jpeg',
|
|
306
|
+
},
|
|
307
|
+
],
|
|
308
|
+
})}
|
|
309
|
+
/>
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
expect(screen.getByTestId('avatar')).toBeInTheDocument()
|
|
313
|
+
expect(screen.getByTestId('avatar')).toHaveAttribute('data-user-id', 'user-1')
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
it('does not render Avatar for own messages', () => {
|
|
317
|
+
renderWithProviders(
|
|
318
|
+
<MediaMessage
|
|
319
|
+
isMyMessage={true}
|
|
320
|
+
message={msg({
|
|
321
|
+
attachments: [
|
|
322
|
+
{
|
|
323
|
+
type: 'image',
|
|
324
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
325
|
+
mime_type: 'image/jpeg',
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
})}
|
|
329
|
+
/>
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
expect(screen.queryByTestId('avatar')).not.toBeInTheDocument()
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
it('applies the --me class for own messages', () => {
|
|
336
|
+
const { container } = renderWithProviders(
|
|
337
|
+
<MediaMessage
|
|
338
|
+
isMyMessage={true}
|
|
339
|
+
message={msg({
|
|
340
|
+
attachments: [
|
|
341
|
+
{
|
|
342
|
+
type: 'image',
|
|
343
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
344
|
+
mime_type: 'image/jpeg',
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
})}
|
|
348
|
+
/>
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
expect(container.firstChild).toHaveClass('str-chat__message--me')
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
it('applies the --other class for messages from other users', () => {
|
|
355
|
+
const { container } = renderWithProviders(
|
|
356
|
+
<MediaMessage
|
|
357
|
+
isMyMessage={false}
|
|
358
|
+
message={msg({
|
|
359
|
+
attachments: [
|
|
360
|
+
{
|
|
361
|
+
type: 'image',
|
|
362
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
363
|
+
mime_type: 'image/jpeg',
|
|
364
|
+
},
|
|
365
|
+
],
|
|
366
|
+
})}
|
|
367
|
+
/>
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
expect(container.firstChild).toHaveClass('str-chat__message--other')
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
it('renders nothing when no attachments', () => {
|
|
374
|
+
const { container } = renderWithProviders(
|
|
375
|
+
<MediaMessage message={msg({ attachments: [] })} />
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
expect(container.firstChild).toBeNull()
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
it('renders a link card for a link attachment', () => {
|
|
382
|
+
renderWithProviders(
|
|
383
|
+
<MediaMessage
|
|
384
|
+
message={msg({
|
|
385
|
+
attachments: [
|
|
386
|
+
{
|
|
387
|
+
type: 'link',
|
|
388
|
+
og_scrape_url: 'https://linktr.ee/someone',
|
|
389
|
+
title: 'My Linktree',
|
|
390
|
+
text: 'Check out my links',
|
|
391
|
+
image_url: 'https://cdn.example.com/thumb.jpg',
|
|
392
|
+
},
|
|
393
|
+
],
|
|
394
|
+
})}
|
|
395
|
+
/>
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
const link = screen.getByRole('link')
|
|
399
|
+
expect(link).toHaveAttribute('href', 'https://linktr.ee/someone')
|
|
400
|
+
expect(screen.getByText('My Linktree')).toBeInTheDocument()
|
|
401
|
+
expect(screen.getByText('Check out my links')).toBeInTheDocument()
|
|
402
|
+
expect(screen.getByText('https://linktr.ee/someone')).toBeInTheDocument()
|
|
403
|
+
const img = screen.getByRole('img', { name: 'My Linktree' })
|
|
404
|
+
expect(img).toHaveAttribute('src', 'https://cdn.example.com/thumb.jpg')
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
it('renders a link fallback icon when link has no image', () => {
|
|
408
|
+
renderWithProviders(
|
|
409
|
+
<MediaMessage
|
|
410
|
+
message={msg({
|
|
411
|
+
attachments: [
|
|
412
|
+
{
|
|
413
|
+
type: 'link',
|
|
414
|
+
og_scrape_url: 'https://linktr.ee/someone',
|
|
415
|
+
title: 'My Linktree',
|
|
416
|
+
},
|
|
417
|
+
],
|
|
418
|
+
})}
|
|
419
|
+
/>
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
expect(screen.queryByRole('img')).not.toBeInTheDocument()
|
|
423
|
+
expect(screen.getByText('My Linktree')).toBeInTheDocument()
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
it('uses dark card background for sent messages', () => {
|
|
427
|
+
const { container } = renderWithProviders(
|
|
428
|
+
<MediaMessage
|
|
429
|
+
isMyMessage={true}
|
|
430
|
+
message={msg({
|
|
431
|
+
attachments: [
|
|
432
|
+
{
|
|
433
|
+
type: 'image',
|
|
434
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
435
|
+
mime_type: 'image/jpeg',
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
})}
|
|
439
|
+
/>
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
expect(container.querySelector('.bg-\\[\\#121110\\]')).toBeInTheDocument()
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
it('uses light card background for received messages', () => {
|
|
446
|
+
const { container } = renderWithProviders(
|
|
447
|
+
<MediaMessage
|
|
448
|
+
isMyMessage={false}
|
|
449
|
+
message={msg({
|
|
450
|
+
attachments: [
|
|
451
|
+
{
|
|
452
|
+
type: 'image',
|
|
453
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
454
|
+
mime_type: 'image/jpeg',
|
|
455
|
+
},
|
|
456
|
+
],
|
|
457
|
+
})}
|
|
458
|
+
/>
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
expect(container.querySelector('.bg-\\[\\#F3F3F1\\]')).toBeInTheDocument()
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
it('shows download button for image attachment', () => {
|
|
465
|
+
renderWithProviders(
|
|
466
|
+
<MediaMessage
|
|
467
|
+
message={msg({
|
|
468
|
+
attachments: [
|
|
469
|
+
{
|
|
470
|
+
type: 'image',
|
|
471
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
472
|
+
mime_type: 'image/jpeg',
|
|
473
|
+
title: 'My Photo',
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
})}
|
|
477
|
+
/>
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
it('shows download button for audio attachment', () => {
|
|
484
|
+
renderWithProviders(
|
|
485
|
+
<MediaMessage
|
|
486
|
+
message={msg({
|
|
487
|
+
attachments: [
|
|
488
|
+
{
|
|
489
|
+
type: 'audio',
|
|
490
|
+
asset_url: 'https://cdn.example.com/track.mp3',
|
|
491
|
+
mime_type: 'audio/mpeg',
|
|
492
|
+
title: 'My Track',
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
})}
|
|
496
|
+
/>
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
it('does not show download or expand buttons for link cards', () => {
|
|
503
|
+
renderWithProviders(
|
|
504
|
+
<MediaMessage
|
|
505
|
+
message={msg({
|
|
506
|
+
attachments: [
|
|
507
|
+
{
|
|
508
|
+
type: 'link',
|
|
509
|
+
og_scrape_url: 'https://linktr.ee/someone',
|
|
510
|
+
title: 'My Linktree',
|
|
511
|
+
},
|
|
512
|
+
],
|
|
513
|
+
})}
|
|
514
|
+
/>
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
expect(screen.queryByRole('button', { name: 'Download' })).not.toBeInTheDocument()
|
|
518
|
+
expect(screen.queryByRole('button', { name: 'View full screen' })).not.toBeInTheDocument()
|
|
519
|
+
})
|
|
520
|
+
})
|