@linktr.ee/messaging-react 4.4.3 → 4.4.4-rc-1788190776
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/AttachmentCard-BbsjzdLJ.cjs +2 -0
- package/dist/AttachmentCard-BbsjzdLJ.cjs.map +1 -0
- package/dist/{AttachmentCard-BqwWgqvi.js → AttachmentCard-DSekwIOA.js} +35 -20
- package/dist/AttachmentCard-DSekwIOA.js.map +1 -0
- package/dist/{Card-BIbqWagz.cjs → Card-BS6Fza2a.cjs} +2 -2
- package/dist/{Card-BIbqWagz.cjs.map → Card-BS6Fza2a.cjs.map} +1 -1
- package/dist/{Card-f51K6V7Y.js → Card-BhwBkgxI.js} +2 -2
- package/dist/{Card-f51K6V7Y.js.map → Card-BhwBkgxI.js.map} +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +67 -42
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/AttachmentCard/MediaPlayer.test.tsx +62 -85
- package/src/components/AttachmentCard/MediaPlayer.tsx +14 -2
- package/src/components/AttachmentCard/Thumbnail.test.tsx +37 -46
- package/src/components/AttachmentCard/index.test.tsx +18 -46
- package/src/components/AttachmentCard/index.tsx +8 -2
- package/src/components/AttachmentCard/utils/icons.ts +11 -1
- package/src/components/Avatar/Avatar.test.tsx +37 -64
- package/src/components/Avatar/index.tsx +8 -1
- package/src/components/ChannelList/CustomChannelPreview.test.tsx +19 -19
- package/src/components/ChannelList/CustomChannelPreview.tsx +8 -2
- package/src/components/ChannelView.outbound-resolution.integration.test.tsx +25 -30
- package/src/components/ChannelView.test.tsx +17 -31
- package/src/components/ChannelView.tsx +1 -0
- package/src/components/CustomLinkPreviewList/CustomLinkPreviewList.test.tsx +8 -5
- package/src/components/CustomLinkPreviewList/index.tsx +4 -1
- package/src/components/CustomMessage/StreamAttachmentMessage.test.tsx +26 -21
- package/src/components/CustomMessage/StreamAttachmentMessage.tsx +2 -0
- package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +43 -56
- package/src/components/CustomMessageInput/index.tsx +25 -5
- package/src/components/CustomSystemMessage/CustomSystemMessage.test.tsx +17 -23
- package/src/components/FaqList/FaqList.test.tsx +5 -4
- package/src/components/FaqList/index.tsx +6 -1
- package/src/components/LinkAttachment/LinkAttachment.test.tsx +70 -81
- package/src/components/LinkAttachment/components/_shared/BubbleTail.test.tsx +1 -0
- package/src/components/LinkAttachment/components/_shared/CardBody.test.tsx +20 -61
- package/src/components/LinkAttachment/components/_shared/CardBody.tsx +10 -2
- package/src/components/LinkAttachment/components/_shared/CardCta.test.tsx +1 -21
- package/src/components/LinkAttachment/components/_shared/CardShell.test.tsx +11 -37
- package/src/components/LinkAttachment/components/_shared/CardShell.tsx +5 -2
- package/src/components/LinkAttachment/components/_shared/CardThumbnail.test.tsx +65 -72
- package/src/components/LinkAttachment/components/_shared/CardThumbnail.tsx +13 -2
- package/src/components/MessageAttachment/MessageAttachment.test.tsx +25 -8
- package/src/components/MessageAttachment/_shared/CompactDocumentRow.test.tsx +5 -19
- package/src/components/MessageAttachment/_shared/MediaStackGrid.test.tsx +7 -9
- package/src/components/MessageAttachment/_shared/VideoViewer.test.tsx +9 -2
- package/src/components/MessageAttachment/_shared/VideoViewer.tsx +1 -0
- package/src/components/MessageAttachment/_shared/ViewerShell.test.tsx +2 -2
- package/src/components/MessageBubble/MessageBubble.test.tsx +0 -1
- package/src/components/RichCard/RichCard.test.tsx +24 -54
- package/src/components/RichCard/RichCardBody.tsx +4 -1
- package/src/hooks/useChannelModerationActions.ts +15 -30
- package/src/logging/index.test.tsx +1 -0
- package/src/providers/MessagingProvider.test.tsx +37 -41
- package/dist/AttachmentCard-BqwWgqvi.js.map +0 -1
- package/dist/AttachmentCard-DUrgGRsq.cjs +0 -2
- package/dist/AttachmentCard-DUrgGRsq.cjs.map +0 -1
|
@@ -97,7 +97,7 @@ const CardShell: React.FC<CardShellProps> = ({
|
|
|
97
97
|
accentHex,
|
|
98
98
|
fixedHeight = false,
|
|
99
99
|
busy = false,
|
|
100
|
-
'data-testid': dataTestId,
|
|
100
|
+
'data-testid': dataTestId = 'link-card',
|
|
101
101
|
}) => {
|
|
102
102
|
const isInteractive = href != null || onClick != null
|
|
103
103
|
const className = classNames(
|
|
@@ -138,7 +138,10 @@ const CardShell: React.FC<CardShellProps> = ({
|
|
|
138
138
|
: undefined
|
|
139
139
|
|
|
140
140
|
const corner = topRight ? (
|
|
141
|
-
<div
|
|
141
|
+
<div
|
|
142
|
+
data-testid="card-shell-top-right"
|
|
143
|
+
className="pointer-events-auto absolute right-3 top-3 z-10"
|
|
144
|
+
>
|
|
142
145
|
{topRight}
|
|
143
146
|
</div>
|
|
144
147
|
) : null
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
cleanup,
|
|
6
|
+
renderWithProviders,
|
|
7
|
+
screen,
|
|
8
|
+
fireEvent,
|
|
9
|
+
} from '../../../../test/utils'
|
|
5
10
|
|
|
6
11
|
import CardThumbnail, {
|
|
7
12
|
AUDIO_BG_CLASS,
|
|
@@ -53,7 +58,7 @@ describe('AUDIO_BG_CLASS', () => {
|
|
|
53
58
|
|
|
54
59
|
describe('CardThumbnail', () => {
|
|
55
60
|
it('collapses the hero to a padded native audio player', () => {
|
|
56
|
-
|
|
61
|
+
renderWithProviders(
|
|
57
62
|
<CardThumbnail
|
|
58
63
|
variant="dark"
|
|
59
64
|
mimeType="audio/mpeg"
|
|
@@ -61,18 +66,17 @@ describe('CardThumbnail', () => {
|
|
|
61
66
|
thumbnailUrl={IMAGE_SRC}
|
|
62
67
|
/>
|
|
63
68
|
)
|
|
64
|
-
const audio =
|
|
65
|
-
expect(audio).
|
|
66
|
-
expect(audio
|
|
67
|
-
expect(audio
|
|
68
|
-
expect(audio?.getAttribute('preload')).toBe('metadata')
|
|
69
|
+
const audio = screen.getByTestId('card-thumbnail-audio')
|
|
70
|
+
expect(audio).toHaveAttribute('src', AUDIO_SRC)
|
|
71
|
+
expect(audio).toHaveAttribute('controls')
|
|
72
|
+
expect(audio).toHaveAttribute('preload', 'metadata')
|
|
69
73
|
// The hero region (and its artwork) is gone entirely on this branch.
|
|
70
|
-
expect(
|
|
71
|
-
expect(
|
|
74
|
+
expect(screen.queryAllByRole('img', { hidden: true })).toHaveLength(0)
|
|
75
|
+
expect(screen.queryByTestId('card-thumbnail-hero')).not.toBeInTheDocument()
|
|
72
76
|
})
|
|
73
77
|
|
|
74
78
|
it('keeps the skeleton instead of an audio player while loading', () => {
|
|
75
|
-
|
|
79
|
+
renderWithProviders(
|
|
76
80
|
<CardThumbnail
|
|
77
81
|
variant="dark"
|
|
78
82
|
mimeType="audio/mpeg"
|
|
@@ -80,12 +84,12 @@ describe('CardThumbnail', () => {
|
|
|
80
84
|
isLoading
|
|
81
85
|
/>
|
|
82
86
|
)
|
|
83
|
-
expect(
|
|
84
|
-
expect(
|
|
87
|
+
expect(screen.queryByTestId('card-thumbnail-audio')).not.toBeInTheDocument()
|
|
88
|
+
expect(screen.getByTestId('card-thumbnail-skeleton')).toBeInTheDocument()
|
|
85
89
|
})
|
|
86
90
|
|
|
87
91
|
it('renders a video player with the poster over a black hero', () => {
|
|
88
|
-
|
|
92
|
+
renderWithProviders(
|
|
89
93
|
<CardThumbnail
|
|
90
94
|
variant="light"
|
|
91
95
|
mimeType="video/mp4"
|
|
@@ -95,19 +99,16 @@ describe('CardThumbnail', () => {
|
|
|
95
99
|
onImageError={() => {}}
|
|
96
100
|
/>
|
|
97
101
|
)
|
|
98
|
-
const video =
|
|
99
|
-
expect(video
|
|
100
|
-
expect(video
|
|
101
|
-
expect(video
|
|
102
|
-
expect(video
|
|
103
|
-
expect(container.querySelector('div.flex-1')?.className).toContain(
|
|
104
|
-
'bg-black'
|
|
105
|
-
)
|
|
102
|
+
const video = screen.getByTestId('card-thumbnail-video')
|
|
103
|
+
expect(video).toHaveAttribute('src', VIDEO_SRC)
|
|
104
|
+
expect(video).toHaveAttribute('poster', IMAGE_SRC)
|
|
105
|
+
expect(video).toHaveAttribute('controls')
|
|
106
|
+
expect(video).toHaveAttribute('preload', 'metadata')
|
|
106
107
|
})
|
|
107
108
|
|
|
108
109
|
it('probes the video poster with a hidden image that reports failures', () => {
|
|
109
110
|
const onImageError = vi.fn()
|
|
110
|
-
|
|
111
|
+
renderWithProviders(
|
|
111
112
|
<CardThumbnail
|
|
112
113
|
variant="light"
|
|
113
114
|
mimeType="video/mp4"
|
|
@@ -116,7 +117,7 @@ describe('CardThumbnail', () => {
|
|
|
116
117
|
onImageError={onImageError}
|
|
117
118
|
/>
|
|
118
119
|
)
|
|
119
|
-
const probe =
|
|
120
|
+
const probe = screen.queryByRole('img', { hidden: true })
|
|
120
121
|
expect(probe).not.toBeNull()
|
|
121
122
|
expect(probe?.className).toContain('hidden')
|
|
122
123
|
expect(probe?.getAttribute('aria-hidden')).toBe('true')
|
|
@@ -125,7 +126,7 @@ describe('CardThumbnail', () => {
|
|
|
125
126
|
})
|
|
126
127
|
|
|
127
128
|
it('skips the poster probe when there is nothing to report to', () => {
|
|
128
|
-
const
|
|
129
|
+
const view = renderWithProviders(
|
|
129
130
|
<CardThumbnail
|
|
130
131
|
variant="light"
|
|
131
132
|
mimeType="video/mp4"
|
|
@@ -133,9 +134,10 @@ describe('CardThumbnail', () => {
|
|
|
133
134
|
thumbnailUrl={IMAGE_SRC}
|
|
134
135
|
/>
|
|
135
136
|
)
|
|
136
|
-
expect(
|
|
137
|
+
expect(screen.queryAllByRole('img', { hidden: true })).toHaveLength(0)
|
|
138
|
+
view.unmount()
|
|
137
139
|
|
|
138
|
-
|
|
140
|
+
renderWithProviders(
|
|
139
141
|
<CardThumbnail
|
|
140
142
|
variant="light"
|
|
141
143
|
mimeType="video/mp4"
|
|
@@ -143,19 +145,21 @@ describe('CardThumbnail', () => {
|
|
|
143
145
|
onImageError={() => {}}
|
|
144
146
|
/>
|
|
145
147
|
)
|
|
146
|
-
expect(
|
|
147
|
-
expect(
|
|
148
|
+
expect(screen.queryAllByRole('img', { hidden: true })).toHaveLength(0)
|
|
149
|
+
expect(screen.getByTestId('card-thumbnail-video')).not.toHaveAttribute(
|
|
150
|
+
'poster'
|
|
151
|
+
)
|
|
148
152
|
})
|
|
149
153
|
|
|
150
154
|
it('renders the thumbnail image with the title as its alt text', () => {
|
|
151
|
-
|
|
155
|
+
renderWithProviders(
|
|
152
156
|
<CardThumbnail
|
|
153
157
|
variant="light"
|
|
154
158
|
thumbnailUrl={IMAGE_SRC}
|
|
155
159
|
title="Cover art"
|
|
156
160
|
/>
|
|
157
161
|
)
|
|
158
|
-
const image =
|
|
162
|
+
const image = screen.getByRole('img', { hidden: true })
|
|
159
163
|
expect(image?.getAttribute('src')).toBe(IMAGE_SRC)
|
|
160
164
|
expect(image?.getAttribute('alt')).toBe('Cover art')
|
|
161
165
|
expect(image?.getAttribute('loading')).toBe('lazy')
|
|
@@ -164,60 +168,41 @@ describe('CardThumbnail', () => {
|
|
|
164
168
|
})
|
|
165
169
|
|
|
166
170
|
it('falls back to empty alt text when the card has no title', () => {
|
|
167
|
-
|
|
171
|
+
renderWithProviders(
|
|
168
172
|
<CardThumbnail variant="light" thumbnailUrl={IMAGE_SRC} />
|
|
169
173
|
)
|
|
170
|
-
expect(
|
|
174
|
+
expect(screen.getByRole('img', { hidden: true })).toHaveAttribute('alt', '')
|
|
171
175
|
})
|
|
172
176
|
|
|
173
177
|
it('reports a failing hero image to its owner', () => {
|
|
174
178
|
const onImageError = vi.fn()
|
|
175
|
-
|
|
179
|
+
renderWithProviders(
|
|
176
180
|
<CardThumbnail
|
|
177
181
|
variant="light"
|
|
178
182
|
thumbnailUrl={IMAGE_SRC}
|
|
179
183
|
onImageError={onImageError}
|
|
180
184
|
/>
|
|
181
185
|
)
|
|
182
|
-
fireEvent.error(
|
|
186
|
+
fireEvent.error(screen.getByRole('img', { hidden: true }))
|
|
183
187
|
expect(onImageError).toHaveBeenCalledTimes(1)
|
|
184
188
|
})
|
|
185
189
|
|
|
186
|
-
it('shows a
|
|
187
|
-
|
|
190
|
+
it('shows a type-icon placeholder instead of an image without a thumbnail', () => {
|
|
191
|
+
renderWithProviders(
|
|
188
192
|
<CardThumbnail variant="dark" mimeType="application/pdf" />
|
|
189
193
|
)
|
|
190
|
-
expect(
|
|
191
|
-
|
|
192
|
-
expect(darkPlaceholder?.className).toContain('bg-white/10')
|
|
193
|
-
expect(darkPlaceholder?.querySelector('svg')?.getAttribute('class')).toBe(
|
|
194
|
-
'size-16 text-white/25'
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
const { container: light } = renderWithProviders(
|
|
198
|
-
<CardThumbnail variant="light" />
|
|
199
|
-
)
|
|
200
|
-
const lightPlaceholder = light.querySelector('div.items-center')
|
|
201
|
-
expect(lightPlaceholder?.className).toContain('bg-black/5')
|
|
202
|
-
expect(lightPlaceholder?.querySelector('svg')?.getAttribute('class')).toBe(
|
|
203
|
-
'size-16 text-black/25'
|
|
204
|
-
)
|
|
194
|
+
expect(screen.queryAllByRole('img', { hidden: true })).toHaveLength(0)
|
|
195
|
+
expect(screen.getByTestId('card-thumbnail-placeholder')).toBeInTheDocument()
|
|
205
196
|
})
|
|
206
197
|
|
|
207
|
-
it('pulses a
|
|
208
|
-
|
|
198
|
+
it('pulses a placeholder block while loading, ignoring the thumbnail', () => {
|
|
199
|
+
renderWithProviders(
|
|
209
200
|
<CardThumbnail variant="dark" thumbnailUrl={IMAGE_SRC} isLoading />
|
|
210
201
|
)
|
|
211
|
-
expect(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const { container: light } = renderWithProviders(
|
|
217
|
-
<CardThumbnail variant="light" isLoading />
|
|
218
|
-
)
|
|
219
|
-
expect(light.querySelector('div.animate-pulse')?.className).toContain(
|
|
220
|
-
'bg-black/5'
|
|
202
|
+
expect(screen.queryAllByRole('img', { hidden: true })).toHaveLength(0)
|
|
203
|
+
expect(screen.getByTestId('card-thumbnail-skeleton')).toHaveAttribute(
|
|
204
|
+
'aria-hidden',
|
|
205
|
+
'true'
|
|
221
206
|
)
|
|
222
207
|
})
|
|
223
208
|
|
|
@@ -229,14 +214,22 @@ describe('CardThumbnail', () => {
|
|
|
229
214
|
topRight={<span>right</span>}
|
|
230
215
|
/>
|
|
231
216
|
)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
)
|
|
235
|
-
expect(
|
|
236
|
-
|
|
237
|
-
)
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
217
|
+
const topLeft = screen.getByTestId('card-thumbnail-top-left')
|
|
218
|
+
const topRight = screen.getByTestId('card-thumbnail-top-right')
|
|
219
|
+
expect(topLeft).toHaveTextContent('left')
|
|
220
|
+
expect(topRight).toHaveTextContent('right')
|
|
221
|
+
/* eslint-disable local/no-style-only-assertion -- overlay slots: in flow they would displace the hero instead of sitting over it. */
|
|
222
|
+
expect(topLeft.className).toContain('absolute left-3 top-3')
|
|
223
|
+
expect(topRight.className).toContain('absolute right-3 top-3')
|
|
224
|
+
/* eslint-enable local/no-style-only-assertion */
|
|
225
|
+
|
|
226
|
+
cleanup()
|
|
227
|
+
renderWithProviders(<CardThumbnail variant="dark" />)
|
|
228
|
+
expect(
|
|
229
|
+
screen.queryByTestId('card-thumbnail-top-left')
|
|
230
|
+
).not.toBeInTheDocument()
|
|
231
|
+
expect(
|
|
232
|
+
screen.queryByTestId('card-thumbnail-top-right')
|
|
233
|
+
).not.toBeInTheDocument()
|
|
241
234
|
})
|
|
242
235
|
})
|
|
@@ -110,6 +110,7 @@ const CardThumbnail: React.FC<CardThumbnailProps> = ({
|
|
|
110
110
|
<div className="p-3">
|
|
111
111
|
<audio
|
|
112
112
|
{...nativePlayerProps}
|
|
113
|
+
data-testid="card-thumbnail-audio"
|
|
113
114
|
src={sourceUrl}
|
|
114
115
|
controls
|
|
115
116
|
preload="metadata"
|
|
@@ -123,6 +124,7 @@ const CardThumbnail: React.FC<CardThumbnailProps> = ({
|
|
|
123
124
|
|
|
124
125
|
return (
|
|
125
126
|
<div
|
|
127
|
+
data-testid="card-thumbnail-hero"
|
|
126
128
|
className={classNames(
|
|
127
129
|
// `flex-1 min-h-0` inside the shell's 250px column: the hero takes
|
|
128
130
|
// every pixel the chin doesn't, which is 168px at a two-line title
|
|
@@ -138,6 +140,7 @@ const CardThumbnail: React.FC<CardThumbnailProps> = ({
|
|
|
138
140
|
// not in either consumer's, so it would compile to nothing in
|
|
139
141
|
// frontyard and profiles while looking right in this Storybook.
|
|
140
142
|
<div
|
|
143
|
+
data-testid="card-thumbnail-skeleton"
|
|
141
144
|
className={classNames(
|
|
142
145
|
'h-full w-full animate-pulse',
|
|
143
146
|
PLACEHOLDER_BG[variant]
|
|
@@ -147,6 +150,7 @@ const CardThumbnail: React.FC<CardThumbnailProps> = ({
|
|
|
147
150
|
) : isPlayableVideo ? (
|
|
148
151
|
<>
|
|
149
152
|
<video
|
|
153
|
+
data-testid="card-thumbnail-video"
|
|
150
154
|
src={sourceUrl}
|
|
151
155
|
poster={optimizedThumbnailUrl}
|
|
152
156
|
controls
|
|
@@ -190,6 +194,7 @@ const CardThumbnail: React.FC<CardThumbnailProps> = ({
|
|
|
190
194
|
/>
|
|
191
195
|
) : (
|
|
192
196
|
<div
|
|
197
|
+
data-testid="card-thumbnail-placeholder"
|
|
193
198
|
className={classNames(
|
|
194
199
|
'flex h-full w-full items-center justify-center',
|
|
195
200
|
PLACEHOLDER_BG[variant]
|
|
@@ -203,12 +208,18 @@ const CardThumbnail: React.FC<CardThumbnailProps> = ({
|
|
|
203
208
|
)}
|
|
204
209
|
|
|
205
210
|
{topLeft ? (
|
|
206
|
-
<div
|
|
211
|
+
<div
|
|
212
|
+
data-testid="card-thumbnail-top-left"
|
|
213
|
+
className="pointer-events-auto absolute left-3 top-3 z-10"
|
|
214
|
+
>
|
|
207
215
|
{topLeft}
|
|
208
216
|
</div>
|
|
209
217
|
) : null}
|
|
210
218
|
{topRight ? (
|
|
211
|
-
<div
|
|
219
|
+
<div
|
|
220
|
+
data-testid="card-thumbnail-top-right"
|
|
221
|
+
className="pointer-events-auto absolute right-3 top-3 z-10"
|
|
222
|
+
>
|
|
212
223
|
{topRight}
|
|
213
224
|
</div>
|
|
214
225
|
) : null}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
fireEvent,
|
|
6
|
+
renderWithProviders,
|
|
7
|
+
screen,
|
|
8
|
+
within,
|
|
9
|
+
} from '../../test/utils'
|
|
5
10
|
|
|
6
11
|
import { triggerDownload } from './_shared/triggerDownload'
|
|
7
12
|
|
|
@@ -365,6 +370,7 @@ describe('MessageAttachment.Bubble geometry overrides', () => {
|
|
|
365
370
|
filename="file.zip"
|
|
366
371
|
/>
|
|
367
372
|
)
|
|
373
|
+
// eslint-disable-next-line local/no-style-only-assertion -- the override contract above, not the values: an appended radius silently loses to the corner table.
|
|
368
374
|
expect(screen.getByTestId('file-attachment')).toHaveClass(
|
|
369
375
|
'w-[280px]',
|
|
370
376
|
'px-2',
|
|
@@ -378,6 +384,7 @@ describe('MessageAttachment.Bubble geometry overrides', () => {
|
|
|
378
384
|
<MessageAttachment.Image.Sent src="https://cdn.example.com/photo.jpg" />
|
|
379
385
|
)
|
|
380
386
|
const bubble = screen.getByTestId('image-attachment')
|
|
387
|
+
// eslint-disable-next-line local/no-style-only-assertion -- the override contract above, not the values: an appended radius silently loses to the corner table.
|
|
381
388
|
expect(bubble).toHaveClass('w-fit', 'p-0.5', 'rounded-[20px]')
|
|
382
389
|
expect(bubble.className).not.toMatch(
|
|
383
390
|
/w-\[280px\]|px-2|py-2|rounded-tl-\[18px\]/
|
|
@@ -912,8 +919,10 @@ describe('MessageAttachment.Video single-card aspect', () => {
|
|
|
912
919
|
/>
|
|
913
920
|
)
|
|
914
921
|
expect(
|
|
915
|
-
screen.getByTestId('video-attachment').
|
|
916
|
-
|
|
922
|
+
within(screen.getByTestId('video-attachment')).queryAllByRole('img', {
|
|
923
|
+
hidden: true,
|
|
924
|
+
})
|
|
925
|
+
).toHaveLength(0)
|
|
917
926
|
// Clamped to MIN_ASPECT: a true 9:16 would render a 587px-tall card, so
|
|
918
927
|
// portrait pins at 4:5 until design asks for a full-height card.
|
|
919
928
|
expect(mediaAspect()).toBe(String(4 / 5))
|
|
@@ -1017,8 +1026,10 @@ describe('MessageAttachment.Video single-card aspect', () => {
|
|
|
1017
1026
|
<MessageAttachment.Video.Received src="https://cdn.example.com/clip.mp4" />
|
|
1018
1027
|
)
|
|
1019
1028
|
expect(
|
|
1020
|
-
screen.getByTestId('video-attachment').
|
|
1021
|
-
|
|
1029
|
+
within(screen.getByTestId('video-attachment')).queryAllByRole('img', {
|
|
1030
|
+
hidden: true,
|
|
1031
|
+
})
|
|
1032
|
+
).toHaveLength(0)
|
|
1022
1033
|
expect(mediaAspect()).toBe(String(1))
|
|
1023
1034
|
})
|
|
1024
1035
|
|
|
@@ -1142,12 +1153,18 @@ describe('MessageAttachment lazy-loading defaults', () => {
|
|
|
1142
1153
|
// on the raw (un-optimised) source. The element being absent
|
|
1143
1154
|
// while closed is therefore the only thing stopping a scrolled
|
|
1144
1155
|
// thread from downloading every full-resolution original.
|
|
1145
|
-
expect(
|
|
1156
|
+
expect(
|
|
1157
|
+
within(screen.getByTestId('image-viewer')).queryAllByRole('img', {
|
|
1158
|
+
hidden: true,
|
|
1159
|
+
})
|
|
1160
|
+
).toHaveLength(0)
|
|
1146
1161
|
|
|
1147
1162
|
fireEvent.click(screen.getByLabelText('Open image 1 of 1'))
|
|
1148
1163
|
expect(
|
|
1149
|
-
screen.getByTestId('image-viewer').
|
|
1150
|
-
|
|
1164
|
+
within(screen.getByTestId('image-viewer')).getByRole('img', {
|
|
1165
|
+
hidden: true,
|
|
1166
|
+
})
|
|
1167
|
+
).toBeInTheDocument()
|
|
1151
1168
|
})
|
|
1152
1169
|
})
|
|
1153
1170
|
|
|
@@ -17,7 +17,7 @@ describe('CompactDocumentRow', () => {
|
|
|
17
17
|
})
|
|
18
18
|
|
|
19
19
|
it('renders metadata only when it has a value and defaults MIME type', () => {
|
|
20
|
-
const {
|
|
20
|
+
const { rerender } = renderWithProviders(
|
|
21
21
|
<CompactDocumentRow
|
|
22
22
|
variant="dark"
|
|
23
23
|
filename="report.pdf"
|
|
@@ -33,7 +33,7 @@ describe('CompactDocumentRow', () => {
|
|
|
33
33
|
/>
|
|
34
34
|
)
|
|
35
35
|
expect(screen.queryByText(/·/)).toBeNull()
|
|
36
|
-
|
|
36
|
+
expect(screen.getByTestId('type-icon-generic')).toBeInTheDocument()
|
|
37
37
|
rerender(
|
|
38
38
|
<CompactDocumentRow
|
|
39
39
|
variant="dark"
|
|
@@ -41,14 +41,12 @@ describe('CompactDocumentRow', () => {
|
|
|
41
41
|
mimeType="application/pdf"
|
|
42
42
|
/>
|
|
43
43
|
)
|
|
44
|
-
expect(
|
|
45
|
-
genericIconMarkup
|
|
46
|
-
)
|
|
44
|
+
expect(screen.getByTestId('type-icon-pdf')).toBeInTheDocument()
|
|
47
45
|
})
|
|
48
46
|
|
|
49
|
-
it('maps variant
|
|
47
|
+
it('maps the variant onto the activatable body treatment', () => {
|
|
50
48
|
const onActivate = vi.fn()
|
|
51
|
-
const {
|
|
49
|
+
const { rerender } = renderWithProviders(
|
|
52
50
|
<CompactDocumentRow
|
|
53
51
|
variant="dark"
|
|
54
52
|
filename="report.pdf"
|
|
@@ -56,12 +54,6 @@ describe('CompactDocumentRow', () => {
|
|
|
56
54
|
activateLabel="Open report"
|
|
57
55
|
/>
|
|
58
56
|
)
|
|
59
|
-
const darkMetadata = screen.getByText('PDF').className
|
|
60
|
-
const darkIconTile = container.querySelector('div[aria-hidden]')
|
|
61
|
-
const darkTileClasses = darkIconTile?.className
|
|
62
|
-
const darkIconClasses = darkIconTile
|
|
63
|
-
?.querySelector('svg')
|
|
64
|
-
?.getAttribute('class')
|
|
65
57
|
expect(screen.getByRole('button', { name: 'Open report' })).toHaveClass(
|
|
66
58
|
'hover:bg-white/[0.04]'
|
|
67
59
|
)
|
|
@@ -74,12 +66,6 @@ describe('CompactDocumentRow', () => {
|
|
|
74
66
|
activateLabel="Open report"
|
|
75
67
|
/>
|
|
76
68
|
)
|
|
77
|
-
expect(screen.getByText('PDF').className).not.toBe(darkMetadata)
|
|
78
|
-
const lightIconTile = container.querySelector('div[aria-hidden]')
|
|
79
|
-
expect(lightIconTile?.className).not.toBe(darkTileClasses)
|
|
80
|
-
expect(lightIconTile?.querySelector('svg')?.getAttribute('class')).not.toBe(
|
|
81
|
-
darkIconClasses
|
|
82
|
-
)
|
|
83
69
|
expect(screen.getByRole('button', { name: 'Open report' })).toHaveClass(
|
|
84
70
|
'hover:bg-black/[0.04]'
|
|
85
71
|
)
|
|
@@ -30,14 +30,14 @@ describe('MediaStackGrid', () => {
|
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
it('clamps visible tiles and places overflow on the last tile', () => {
|
|
33
|
-
const {
|
|
33
|
+
const { rerender } = renderWithProviders(
|
|
34
34
|
<MediaStackGrid tiles={tiles(6)} maxVisible={4} />
|
|
35
35
|
)
|
|
36
|
-
expect(
|
|
36
|
+
expect(screen.getAllByText(/tile/)).toHaveLength(4)
|
|
37
37
|
expect(screen.getByText('+2')).toBeInTheDocument()
|
|
38
38
|
expect(screen.getByText('+2').parentElement).toHaveTextContent('tile 4')
|
|
39
39
|
rerender(<MediaStackGrid tiles={tiles(2)} maxVisible={4} />)
|
|
40
|
-
expect(
|
|
40
|
+
expect(screen.getAllByText(/tile/)).toHaveLength(2)
|
|
41
41
|
expect(screen.queryByText(/^\+/)).toBeNull()
|
|
42
42
|
rerender(<MediaStackGrid tiles={tiles(1)} singleAspectRatio={0.5} />)
|
|
43
43
|
expect(
|
|
@@ -53,20 +53,18 @@ describe('MediaStackGrid', () => {
|
|
|
53
53
|
])(
|
|
54
54
|
'shows overflow on the last visible tile when maxVisible is %s',
|
|
55
55
|
(maxVisible, badge, lastTile) => {
|
|
56
|
-
|
|
56
|
+
renderWithProviders(
|
|
57
57
|
<MediaStackGrid tiles={tiles(5)} maxVisible={maxVisible} />
|
|
58
58
|
)
|
|
59
|
-
expect(
|
|
59
|
+
expect(screen.getAllByText(/tile/)).toHaveLength(maxVisible)
|
|
60
60
|
expect(screen.getByText(badge)).toBeInTheDocument()
|
|
61
61
|
expect(screen.getByText(badge).parentElement).toHaveTextContent(lastTile)
|
|
62
62
|
}
|
|
63
63
|
)
|
|
64
64
|
|
|
65
65
|
it('shows overflow on the single visible tile', () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)
|
|
69
|
-
expect(container.querySelectorAll('span')).toHaveLength(1)
|
|
66
|
+
renderWithProviders(<MediaStackGrid tiles={tiles(3)} maxVisible={1} />)
|
|
67
|
+
expect(screen.getAllByText(/tile/)).toHaveLength(1)
|
|
70
68
|
expect(screen.getByText('+2').parentElement).toHaveTextContent('tile 1')
|
|
71
69
|
})
|
|
72
70
|
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
fireEvent,
|
|
6
6
|
renderWithProviders,
|
|
7
7
|
screen,
|
|
8
|
+
within,
|
|
8
9
|
} from '../../../test/utils'
|
|
9
10
|
|
|
10
11
|
import VideoViewer from './VideoViewer'
|
|
@@ -106,7 +107,9 @@ describe('VideoViewer', () => {
|
|
|
106
107
|
// Gone once the dialog is: a `<video preload="metadata">` left in a
|
|
107
108
|
// closed viewer fetches a header per bubble in the thread.
|
|
108
109
|
expect(
|
|
109
|
-
screen.getByTestId('video-viewer').
|
|
110
|
+
within(screen.getByTestId('video-viewer')).queryByTestId(
|
|
111
|
+
'video-viewer-media'
|
|
112
|
+
)
|
|
110
113
|
).toBeNull()
|
|
111
114
|
} finally {
|
|
112
115
|
vi.useRealTimers()
|
|
@@ -117,6 +120,10 @@ describe('VideoViewer', () => {
|
|
|
117
120
|
renderWithProviders(
|
|
118
121
|
<VideoViewer open={false} onClose={vi.fn()} items={[items[0]]} />
|
|
119
122
|
)
|
|
120
|
-
expect(
|
|
123
|
+
expect(
|
|
124
|
+
within(screen.getByTestId('video-viewer')).queryByTestId(
|
|
125
|
+
'video-viewer-media'
|
|
126
|
+
)
|
|
127
|
+
).toBeNull()
|
|
121
128
|
})
|
|
122
129
|
})
|
|
@@ -131,6 +131,7 @@ const VideoViewer: React.FC<VideoViewerProps> = ({
|
|
|
131
131
|
{mounted ? (
|
|
132
132
|
<video
|
|
133
133
|
ref={videoRef}
|
|
134
|
+
data-testid="video-viewer-media"
|
|
134
135
|
// Forcing a key swap on item change ensures the new source
|
|
135
136
|
// mounts a fresh element instead of reusing the previous
|
|
136
137
|
// playback state — keeps the video paused-at-start when
|
|
@@ -123,12 +123,12 @@ describe('ViewerShell', () => {
|
|
|
123
123
|
throw new Error('not supported')
|
|
124
124
|
})
|
|
125
125
|
defineDialogMethod('showModal', showModal)
|
|
126
|
-
|
|
126
|
+
renderWithProviders(
|
|
127
127
|
<ViewerShell open onClose={vi.fn()} data-testid="viewer">
|
|
128
128
|
content
|
|
129
129
|
</ViewerShell>
|
|
130
130
|
)
|
|
131
|
-
expect(
|
|
131
|
+
expect(screen.getByRole('dialog')).toHaveAttribute('open')
|
|
132
132
|
expect(showModal).toHaveBeenCalledOnce()
|
|
133
133
|
})
|
|
134
134
|
|