@linktr.ee/messaging-react 1.37.0 → 1.38.0
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-DwgUtqsA.js +127 -0
- package/dist/Card-DwgUtqsA.js.map +1 -0
- package/dist/Card-RgHsp9x1.js +138 -0
- package/dist/Card-RgHsp9x1.js.map +1 -0
- package/dist/{index-DOsC03ZN.js → index-B_4pciGp.js} +1411 -1358
- package/dist/index-B_4pciGp.js.map +1 -0
- package/dist/index.d.ts +21 -1
- package/dist/index.js +15 -13
- package/package.json +1 -1
- package/src/components/{LockedAttachment/components → AttachmentCard}/MediaPlayer.tsx +4 -3
- package/src/components/AttachmentCard/Thumbnail.tsx +150 -0
- package/src/components/AttachmentCard/index.tsx +114 -0
- package/src/components/LockedAttachment/components/Creator/Card.tsx +123 -113
- package/src/components/LockedAttachment/components/Visitor/Card.tsx +43 -42
- package/src/components/LockedAttachment/components/Visitor/LockBadge.tsx +12 -0
- package/src/components/MediaMessage/MediaMessage.stories.tsx +45 -4
- package/src/components/MediaMessage/MediaMessage.test.tsx +151 -153
- package/src/components/MediaMessage/index.tsx +239 -349
- package/src/index.ts +7 -3
- package/dist/Card-BHrnmHeu.js +0 -167
- package/dist/Card-BHrnmHeu.js.map +0 -1
- package/dist/Card-D4vEgqWt.js +0 -195
- package/dist/Card-D4vEgqWt.js.map +0 -1
- package/dist/index-DOsC03ZN.js.map +0 -1
- package/src/components/LockedAttachment/components/Creator/CardThumbnail.tsx +0 -114
- package/src/components/LockedAttachment/components/Visitor/CardThumbnail.tsx +0 -81
- /package/src/components/{LockedAttachment → AttachmentCard}/utils/icons.ts +0 -0
- /package/src/components/{LockedAttachment → AttachmentCard}/utils/mimeType.test.ts +0 -0
- /package/src/components/{LockedAttachment → AttachmentCard}/utils/mimeType.ts +0 -0
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import type { LocalMessage } from 'stream-chat'
|
|
3
|
-
import {
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
4
4
|
|
|
5
5
|
import { renderWithProviders, screen, fireEvent } from '../../test/utils'
|
|
6
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
|
-
})
|
|
7
|
+
import { MediaMessage, resolveLinkAttachment } from '.'
|
|
17
8
|
|
|
18
9
|
vi.mock('../Avatar', () => ({
|
|
19
10
|
Avatar: ({ id }: { id: string }) => (
|
|
@@ -21,15 +12,13 @@ vi.mock('../Avatar', () => ({
|
|
|
21
12
|
),
|
|
22
13
|
}))
|
|
23
14
|
|
|
24
|
-
vi.mock('../
|
|
15
|
+
vi.mock('../AttachmentCard/MediaPlayer', () => ({
|
|
25
16
|
default: ({
|
|
26
17
|
source,
|
|
27
18
|
mimeType,
|
|
28
|
-
onContainerClick,
|
|
29
19
|
}: {
|
|
30
20
|
source: string
|
|
31
21
|
mimeType: string
|
|
32
|
-
onContainerClick?: (e: React.MouseEvent) => void
|
|
33
22
|
}) => (
|
|
34
23
|
<div
|
|
35
24
|
role="button"
|
|
@@ -37,17 +26,15 @@ vi.mock('../LockedAttachment/components/MediaPlayer', () => ({
|
|
|
37
26
|
data-testid="media-player"
|
|
38
27
|
data-source={source}
|
|
39
28
|
data-mime-type={mimeType}
|
|
40
|
-
onClick={onContainerClick}
|
|
41
|
-
onKeyDown={undefined}
|
|
42
29
|
/>
|
|
43
30
|
),
|
|
44
31
|
}))
|
|
45
32
|
|
|
46
|
-
vi.mock('../
|
|
33
|
+
vi.mock('../AttachmentCard/utils/icons', () => ({
|
|
47
34
|
renderTypeIcon: () => <span data-testid="type-icon" />,
|
|
48
35
|
}))
|
|
49
36
|
|
|
50
|
-
vi.mock('../
|
|
37
|
+
vi.mock('../AttachmentCard/utils/mimeType', () => ({
|
|
51
38
|
getSourceType: (mimeType: string) => {
|
|
52
39
|
if (mimeType.startsWith('video/')) return 'video'
|
|
53
40
|
if (mimeType.startsWith('image/')) return 'image'
|
|
@@ -98,203 +85,195 @@ describe('MediaMessage', () => {
|
|
|
98
85
|
expect(player).toHaveAttribute('data-source', 'https://cdn.example.com/clip.mp4')
|
|
99
86
|
})
|
|
100
87
|
|
|
101
|
-
it('
|
|
88
|
+
it('renders MediaPlayer for an audio attachment', () => {
|
|
102
89
|
renderWithProviders(
|
|
103
90
|
<MediaMessage
|
|
104
91
|
message={msg({
|
|
105
92
|
attachments: [
|
|
106
93
|
{
|
|
107
|
-
type: '
|
|
108
|
-
asset_url: 'https://cdn.example.com/
|
|
109
|
-
mime_type: '
|
|
110
|
-
title: 'My Clip',
|
|
94
|
+
type: 'audio',
|
|
95
|
+
asset_url: 'https://cdn.example.com/track.mp3',
|
|
96
|
+
mime_type: 'audio/mpeg',
|
|
111
97
|
},
|
|
112
98
|
],
|
|
113
99
|
})}
|
|
114
100
|
/>
|
|
115
101
|
)
|
|
116
102
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
103
|
+
expect(screen.getByTestId('media-player')).toHaveAttribute(
|
|
104
|
+
'data-source',
|
|
105
|
+
'https://cdn.example.com/track.mp3'
|
|
106
|
+
)
|
|
120
107
|
})
|
|
121
108
|
|
|
122
|
-
it('renders
|
|
109
|
+
it('renders an img for an image attachment', () => {
|
|
123
110
|
renderWithProviders(
|
|
124
111
|
<MediaMessage
|
|
125
112
|
message={msg({
|
|
126
113
|
attachments: [
|
|
127
114
|
{
|
|
128
|
-
type: '
|
|
129
|
-
|
|
130
|
-
mime_type: '
|
|
115
|
+
type: 'image',
|
|
116
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
117
|
+
mime_type: 'image/jpeg',
|
|
118
|
+
title: 'My Photo',
|
|
131
119
|
},
|
|
132
120
|
],
|
|
133
121
|
})}
|
|
134
122
|
/>
|
|
135
123
|
)
|
|
136
124
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
'https://cdn.example.com/track.mp3'
|
|
140
|
-
)
|
|
125
|
+
const image = screen.getByRole('img', { name: 'My Photo' })
|
|
126
|
+
expect(image).toHaveAttribute('src', 'https://cdn.example.com/photo.jpg')
|
|
141
127
|
})
|
|
142
128
|
|
|
143
|
-
it('
|
|
129
|
+
it('renders unknown file type as icon placeholder, not a link', () => {
|
|
144
130
|
renderWithProviders(
|
|
145
131
|
<MediaMessage
|
|
146
132
|
message={msg({
|
|
147
133
|
attachments: [
|
|
148
134
|
{
|
|
149
|
-
type: '
|
|
150
|
-
asset_url: 'https://cdn.example.com/
|
|
151
|
-
mime_type: '
|
|
152
|
-
title: '
|
|
135
|
+
type: 'file',
|
|
136
|
+
asset_url: 'https://cdn.example.com/data.bin',
|
|
137
|
+
mime_type: 'application/octet-stream',
|
|
138
|
+
title: 'Unknown File',
|
|
153
139
|
},
|
|
154
140
|
],
|
|
155
141
|
})}
|
|
156
142
|
/>
|
|
157
143
|
)
|
|
158
144
|
|
|
159
|
-
expect(screen.queryByRole('
|
|
160
|
-
expect(screen.
|
|
145
|
+
expect(screen.queryByRole('link')).not.toBeInTheDocument()
|
|
146
|
+
expect(screen.getByText('Unknown File')).toBeInTheDocument()
|
|
147
|
+
expect(screen.getAllByTestId('type-icon').length).toBeGreaterThanOrEqual(1)
|
|
161
148
|
})
|
|
162
149
|
|
|
163
|
-
it('
|
|
150
|
+
it('shows title and file size in meta row', () => {
|
|
164
151
|
renderWithProviders(
|
|
165
152
|
<MediaMessage
|
|
166
153
|
message={msg({
|
|
167
154
|
attachments: [
|
|
168
155
|
{
|
|
169
|
-
type: '
|
|
170
|
-
|
|
171
|
-
mime_type: '
|
|
172
|
-
title: '
|
|
156
|
+
type: 'video',
|
|
157
|
+
asset_url: 'https://cdn.example.com/clip.mp4',
|
|
158
|
+
mime_type: 'video/mp4',
|
|
159
|
+
title: 'Clip',
|
|
160
|
+
file_size: 2048,
|
|
173
161
|
},
|
|
174
162
|
],
|
|
175
163
|
})}
|
|
176
164
|
/>
|
|
177
165
|
)
|
|
178
166
|
|
|
179
|
-
|
|
180
|
-
expect(
|
|
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)
|
|
167
|
+
expect(screen.getByText('Clip')).toBeInTheDocument()
|
|
168
|
+
expect(screen.getByText('2.0 KB')).toBeInTheDocument()
|
|
187
169
|
})
|
|
188
170
|
|
|
189
|
-
it('
|
|
171
|
+
it('renders Avatar for a message from another user', () => {
|
|
190
172
|
renderWithProviders(
|
|
191
173
|
<MediaMessage
|
|
174
|
+
isMyMessage={false}
|
|
192
175
|
message={msg({
|
|
193
176
|
attachments: [
|
|
194
177
|
{
|
|
195
178
|
type: 'image',
|
|
196
179
|
image_url: 'https://cdn.example.com/photo.jpg',
|
|
197
180
|
mime_type: 'image/jpeg',
|
|
198
|
-
title: 'My Photo',
|
|
199
181
|
},
|
|
200
182
|
],
|
|
201
183
|
})}
|
|
202
184
|
/>
|
|
203
185
|
)
|
|
204
186
|
|
|
205
|
-
|
|
206
|
-
expect(screen.
|
|
207
|
-
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
187
|
+
expect(screen.getByTestId('avatar')).toBeInTheDocument()
|
|
188
|
+
expect(screen.getByTestId('avatar')).toHaveAttribute('data-user-id', 'user-1')
|
|
208
189
|
})
|
|
209
190
|
|
|
210
|
-
it('
|
|
191
|
+
it('does not render Avatar for own messages', () => {
|
|
211
192
|
renderWithProviders(
|
|
212
193
|
<MediaMessage
|
|
194
|
+
isMyMessage={true}
|
|
213
195
|
message={msg({
|
|
214
196
|
attachments: [
|
|
215
197
|
{
|
|
216
|
-
type: '
|
|
217
|
-
|
|
218
|
-
mime_type: '
|
|
219
|
-
title: 'Annual Report',
|
|
198
|
+
type: 'image',
|
|
199
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
200
|
+
mime_type: 'image/jpeg',
|
|
220
201
|
},
|
|
221
202
|
],
|
|
222
203
|
})}
|
|
223
204
|
/>
|
|
224
205
|
)
|
|
225
206
|
|
|
226
|
-
expect(screen.
|
|
227
|
-
expect(screen.getByText('Annual Report')).toBeInTheDocument()
|
|
207
|
+
expect(screen.queryByTestId('avatar')).not.toBeInTheDocument()
|
|
228
208
|
})
|
|
229
209
|
|
|
230
|
-
it('
|
|
231
|
-
renderWithProviders(
|
|
210
|
+
it('applies the --me class for own messages', () => {
|
|
211
|
+
const { container } = renderWithProviders(
|
|
232
212
|
<MediaMessage
|
|
213
|
+
isMyMessage={true}
|
|
233
214
|
message={msg({
|
|
234
215
|
attachments: [
|
|
235
216
|
{
|
|
236
|
-
type: '
|
|
237
|
-
|
|
238
|
-
mime_type: '
|
|
239
|
-
title: 'Annual Report',
|
|
217
|
+
type: 'image',
|
|
218
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
219
|
+
mime_type: 'image/jpeg',
|
|
240
220
|
},
|
|
241
221
|
],
|
|
242
222
|
})}
|
|
243
223
|
/>
|
|
244
224
|
)
|
|
245
225
|
|
|
246
|
-
|
|
247
|
-
expect(HTMLDialogElement.prototype.showModal).toHaveBeenCalled()
|
|
248
|
-
expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument()
|
|
226
|
+
expect(container.firstChild).toHaveClass('str-chat__message--me')
|
|
249
227
|
})
|
|
250
228
|
|
|
251
|
-
it('
|
|
252
|
-
renderWithProviders(
|
|
229
|
+
it('applies the --other class for messages from other users', () => {
|
|
230
|
+
const { container } = renderWithProviders(
|
|
253
231
|
<MediaMessage
|
|
232
|
+
isMyMessage={false}
|
|
254
233
|
message={msg({
|
|
255
234
|
attachments: [
|
|
256
235
|
{
|
|
257
|
-
type: '
|
|
258
|
-
|
|
259
|
-
mime_type: '
|
|
260
|
-
title: 'Unknown File',
|
|
236
|
+
type: 'image',
|
|
237
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
238
|
+
mime_type: 'image/jpeg',
|
|
261
239
|
},
|
|
262
240
|
],
|
|
263
241
|
})}
|
|
264
242
|
/>
|
|
265
243
|
)
|
|
266
244
|
|
|
267
|
-
|
|
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()
|
|
245
|
+
expect(container.firstChild).toHaveClass('str-chat__message--other')
|
|
273
246
|
})
|
|
274
247
|
|
|
275
|
-
it('
|
|
276
|
-
renderWithProviders(
|
|
248
|
+
it('renders nothing when no attachments', () => {
|
|
249
|
+
const { container } = renderWithProviders(
|
|
250
|
+
<MediaMessage message={msg({ attachments: [] })} />
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
expect(container.firstChild).toBeNull()
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
it('uses dark card background for sent (Creator) messages', () => {
|
|
257
|
+
const { container } = renderWithProviders(
|
|
277
258
|
<MediaMessage
|
|
259
|
+
isMyMessage={true}
|
|
278
260
|
message={msg({
|
|
279
261
|
attachments: [
|
|
280
262
|
{
|
|
281
|
-
type: '
|
|
282
|
-
|
|
283
|
-
mime_type: '
|
|
284
|
-
title: 'Clip',
|
|
285
|
-
file_size: 2048,
|
|
263
|
+
type: 'image',
|
|
264
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
265
|
+
mime_type: 'image/jpeg',
|
|
286
266
|
},
|
|
287
267
|
],
|
|
288
268
|
})}
|
|
289
269
|
/>
|
|
290
270
|
)
|
|
291
271
|
|
|
292
|
-
expect(
|
|
293
|
-
expect(screen.getByText('2.0 KB')).toBeInTheDocument()
|
|
272
|
+
expect(container.querySelector('.bg-\\[\\#121110\\]')).toBeInTheDocument()
|
|
294
273
|
})
|
|
295
274
|
|
|
296
|
-
it('
|
|
297
|
-
renderWithProviders(
|
|
275
|
+
it('uses light card background for received (Visitor) messages', () => {
|
|
276
|
+
const { container } = renderWithProviders(
|
|
298
277
|
<MediaMessage
|
|
299
278
|
isMyMessage={false}
|
|
300
279
|
message={msg({
|
|
@@ -309,31 +288,30 @@ describe('MediaMessage', () => {
|
|
|
309
288
|
/>
|
|
310
289
|
)
|
|
311
290
|
|
|
312
|
-
expect(
|
|
313
|
-
expect(screen.getByTestId('avatar')).toHaveAttribute('data-user-id', 'user-1')
|
|
291
|
+
expect(container.querySelector('.bg-white')).toBeInTheDocument()
|
|
314
292
|
})
|
|
315
293
|
|
|
316
|
-
it('
|
|
294
|
+
it('shows Download action for received (Visitor) image attachment', () => {
|
|
317
295
|
renderWithProviders(
|
|
318
296
|
<MediaMessage
|
|
319
|
-
isMyMessage={true}
|
|
320
297
|
message={msg({
|
|
321
298
|
attachments: [
|
|
322
299
|
{
|
|
323
300
|
type: 'image',
|
|
324
301
|
image_url: 'https://cdn.example.com/photo.jpg',
|
|
325
302
|
mime_type: 'image/jpeg',
|
|
303
|
+
title: 'My Photo',
|
|
326
304
|
},
|
|
327
305
|
],
|
|
328
306
|
})}
|
|
329
307
|
/>
|
|
330
308
|
)
|
|
331
309
|
|
|
332
|
-
expect(screen.
|
|
310
|
+
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
333
311
|
})
|
|
334
312
|
|
|
335
|
-
it('
|
|
336
|
-
|
|
313
|
+
it('does not show literal placeholder title for sent image without title', () => {
|
|
314
|
+
renderWithProviders(
|
|
337
315
|
<MediaMessage
|
|
338
316
|
isMyMessage={true}
|
|
339
317
|
message={msg({
|
|
@@ -348,34 +326,46 @@ describe('MediaMessage', () => {
|
|
|
348
326
|
/>
|
|
349
327
|
)
|
|
350
328
|
|
|
351
|
-
expect(
|
|
329
|
+
expect(screen.queryByText('Attachment title')).not.toBeInTheDocument()
|
|
352
330
|
})
|
|
353
331
|
|
|
354
|
-
it('
|
|
355
|
-
|
|
332
|
+
it('does not show Download button for sent (Creator) image attachment', () => {
|
|
333
|
+
renderWithProviders(
|
|
356
334
|
<MediaMessage
|
|
357
|
-
isMyMessage={
|
|
335
|
+
isMyMessage={true}
|
|
358
336
|
message={msg({
|
|
359
337
|
attachments: [
|
|
360
338
|
{
|
|
361
339
|
type: 'image',
|
|
362
340
|
image_url: 'https://cdn.example.com/photo.jpg',
|
|
363
341
|
mime_type: 'image/jpeg',
|
|
342
|
+
title: 'My Photo',
|
|
364
343
|
},
|
|
365
344
|
],
|
|
366
345
|
})}
|
|
367
346
|
/>
|
|
368
347
|
)
|
|
369
348
|
|
|
370
|
-
expect(
|
|
349
|
+
expect(screen.queryByRole('button', { name: 'Download' })).not.toBeInTheDocument()
|
|
371
350
|
})
|
|
372
351
|
|
|
373
|
-
it('
|
|
374
|
-
|
|
375
|
-
<MediaMessage
|
|
352
|
+
it('shows Download action for received audio attachment', () => {
|
|
353
|
+
renderWithProviders(
|
|
354
|
+
<MediaMessage
|
|
355
|
+
message={msg({
|
|
356
|
+
attachments: [
|
|
357
|
+
{
|
|
358
|
+
type: 'audio',
|
|
359
|
+
asset_url: 'https://cdn.example.com/track.mp3',
|
|
360
|
+
mime_type: 'audio/mpeg',
|
|
361
|
+
title: 'My Track',
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
})}
|
|
365
|
+
/>
|
|
376
366
|
)
|
|
377
367
|
|
|
378
|
-
expect(
|
|
368
|
+
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
379
369
|
})
|
|
380
370
|
|
|
381
371
|
it('renders a link card for a link attachment', () => {
|
|
@@ -423,98 +413,106 @@ describe('MediaMessage', () => {
|
|
|
423
413
|
expect(screen.getByText('My Linktree')).toBeInTheDocument()
|
|
424
414
|
})
|
|
425
415
|
|
|
426
|
-
it('
|
|
427
|
-
|
|
416
|
+
it('does not show download or expand buttons for link cards', () => {
|
|
417
|
+
renderWithProviders(
|
|
428
418
|
<MediaMessage
|
|
429
|
-
isMyMessage={true}
|
|
430
419
|
message={msg({
|
|
431
420
|
attachments: [
|
|
432
421
|
{
|
|
433
|
-
type: '
|
|
434
|
-
|
|
435
|
-
|
|
422
|
+
type: 'link',
|
|
423
|
+
og_scrape_url: 'https://linktr.ee/someone',
|
|
424
|
+
title: 'My Linktree',
|
|
436
425
|
},
|
|
437
426
|
],
|
|
438
427
|
})}
|
|
439
428
|
/>
|
|
440
429
|
)
|
|
441
430
|
|
|
442
|
-
expect(
|
|
431
|
+
expect(screen.queryByRole('button', { name: 'Download' })).not.toBeInTheDocument()
|
|
432
|
+
expect(screen.queryByRole('button', { name: 'View full screen' })).not.toBeInTheDocument()
|
|
443
433
|
})
|
|
444
434
|
|
|
445
|
-
it('
|
|
435
|
+
it('MediaMessage.Visitor renders card without chat shell', () => {
|
|
446
436
|
const { container } = renderWithProviders(
|
|
447
|
-
<MediaMessage
|
|
448
|
-
isMyMessage={false}
|
|
437
|
+
<MediaMessage.Visitor
|
|
449
438
|
message={msg({
|
|
450
439
|
attachments: [
|
|
451
440
|
{
|
|
452
441
|
type: 'image',
|
|
453
442
|
image_url: 'https://cdn.example.com/photo.jpg',
|
|
454
443
|
mime_type: 'image/jpeg',
|
|
444
|
+
title: 'Solo',
|
|
455
445
|
},
|
|
456
446
|
],
|
|
457
447
|
})}
|
|
458
448
|
/>
|
|
459
449
|
)
|
|
460
450
|
|
|
461
|
-
expect(container.querySelector('.
|
|
451
|
+
expect(container.querySelector('.str-chat__message')).not.toBeInTheDocument()
|
|
452
|
+
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
462
453
|
})
|
|
463
454
|
|
|
464
|
-
it('
|
|
465
|
-
renderWithProviders(
|
|
466
|
-
<MediaMessage
|
|
455
|
+
it('MediaMessage.Creator renders card without chat shell', () => {
|
|
456
|
+
const { container } = renderWithProviders(
|
|
457
|
+
<MediaMessage.Creator
|
|
467
458
|
message={msg({
|
|
468
459
|
attachments: [
|
|
469
460
|
{
|
|
470
461
|
type: 'image',
|
|
471
462
|
image_url: 'https://cdn.example.com/photo.jpg',
|
|
472
463
|
mime_type: 'image/jpeg',
|
|
473
|
-
title: 'My Photo',
|
|
474
464
|
},
|
|
475
465
|
],
|
|
476
466
|
})}
|
|
477
467
|
/>
|
|
478
468
|
)
|
|
479
469
|
|
|
480
|
-
expect(
|
|
470
|
+
expect(container.querySelector('.str-chat__message')).not.toBeInTheDocument()
|
|
471
|
+
expect(screen.queryByRole('button', { name: 'Download' })).not.toBeInTheDocument()
|
|
481
472
|
})
|
|
482
473
|
|
|
483
|
-
it('
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
})}
|
|
496
|
-
/>
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
474
|
+
it('resolveLinkAttachment ignores empty-string og_scrape_url without asset_url', () => {
|
|
475
|
+
const message = msg({
|
|
476
|
+
attachments: [
|
|
477
|
+
{
|
|
478
|
+
type: 'image',
|
|
479
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
480
|
+
mime_type: 'image/jpeg',
|
|
481
|
+
og_scrape_url: '',
|
|
482
|
+
},
|
|
483
|
+
],
|
|
484
|
+
})
|
|
485
|
+
expect(resolveLinkAttachment(message)).toBeUndefined()
|
|
500
486
|
})
|
|
501
487
|
|
|
502
|
-
it('
|
|
488
|
+
it('Download button triggers fetch and uses fallback on failure', async () => {
|
|
489
|
+
const fetchSpy = vi.spyOn(global, 'fetch').mockRejectedValue(new Error('fail'))
|
|
490
|
+
const openSpy = vi.spyOn(window, 'open').mockReturnValue({
|
|
491
|
+
location: { href: '' },
|
|
492
|
+
close: vi.fn(),
|
|
493
|
+
} as unknown as Window)
|
|
494
|
+
|
|
503
495
|
renderWithProviders(
|
|
504
496
|
<MediaMessage
|
|
505
497
|
message={msg({
|
|
506
498
|
attachments: [
|
|
507
499
|
{
|
|
508
|
-
type: '
|
|
509
|
-
|
|
510
|
-
|
|
500
|
+
type: 'image',
|
|
501
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
502
|
+
mime_type: 'image/jpeg',
|
|
503
|
+
title: 'My Photo',
|
|
511
504
|
},
|
|
512
505
|
],
|
|
513
506
|
})}
|
|
514
507
|
/>
|
|
515
508
|
)
|
|
516
509
|
|
|
517
|
-
|
|
518
|
-
|
|
510
|
+
fireEvent.click(screen.getByRole('button', { name: 'Download' }))
|
|
511
|
+
await vi.waitFor(() => {
|
|
512
|
+
expect(fetchSpy).toHaveBeenCalled()
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
fetchSpy.mockRestore()
|
|
516
|
+
openSpy.mockRestore()
|
|
519
517
|
})
|
|
520
518
|
})
|