@linktr.ee/messaging-react 4.4.7 → 4.5.0-rc-1788297811
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/assets/index.css +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +58 -43
- package/dist/index.js +1167 -1033
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/AttachmentCard/MediaPlayer.test.tsx +9 -5
- package/src/components/AttachmentCard/Thumbnail.test.tsx +4 -0
- package/src/components/ChannelActionsMenu/ChannelActionsMenu.test.tsx +18 -10
- package/src/components/ChannelList/ChannelListContext.test.tsx +7 -5
- package/src/components/ChannelList/CustomChannelPreview.test.tsx +7 -5
- package/src/components/ChannelList/index.test.tsx +1 -0
- package/src/components/ChannelView.test.tsx +20 -13
- package/src/components/CustomLinkPreviewList/CustomLinkPreviewList.test.tsx +4 -3
- package/src/components/CustomMessage/CustomMessage.test.tsx +6 -5
- package/src/components/CustomMessage/MessageTag.test.tsx +6 -0
- package/src/components/CustomMessage/SentMessageDeliveryStatus.test.tsx +19 -9
- package/src/components/CustomMessage/StreamAttachmentMessage.test.tsx +45 -5
- package/src/components/CustomMessage/StreamAttachmentMessage.tsx +6 -0
- package/src/components/CustomMessage/TipMessage/TipMessage.test.tsx +3 -0
- package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +16 -7
- package/src/components/FaqList/FaqList.test.tsx +20 -12
- package/src/components/LinkAttachment/LinkAttachment.test.tsx +27 -14
- package/src/components/LinkAttachment/components/_shared/BubbleTail.test.tsx +1 -0
- package/src/components/LinkAttachment/components/_shared/CardBody.test.tsx +6 -6
- package/src/components/LinkAttachment/components/_shared/CardCta.test.tsx +8 -5
- package/src/components/LinkAttachment/components/_shared/CardShell.test.tsx +7 -5
- package/src/components/LinkAttachment/components/_shared/CardThumbnail.test.tsx +3 -8
- package/src/components/MessageAttachment/Audio/AudioAttachment.stories.tsx +165 -58
- package/src/components/MessageAttachment/Audio/WaveformAudioRow.test.tsx +155 -0
- package/src/components/MessageAttachment/Audio/WaveformAudioRow.tsx +455 -0
- package/src/components/MessageAttachment/Audio/audioRowRequester.test.ts +24 -0
- package/src/components/MessageAttachment/Audio/audioRowRequester.ts +16 -0
- package/src/components/MessageAttachment/Audio/index.tsx +83 -79
- package/src/components/MessageAttachment/MessageAttachment.behavior.test.tsx +22 -15
- package/src/components/MessageAttachment/MessageAttachment.test.tsx +279 -134
- package/src/components/MessageAttachment/_shared/Bubble.test.tsx +2 -0
- package/src/components/MessageAttachment/_shared/CarouselNav.test.tsx +5 -4
- package/src/components/MessageAttachment/_shared/CompactDocumentRow.test.tsx +4 -3
- package/src/components/MessageAttachment/_shared/DismissButton.test.tsx +4 -3
- package/src/components/MessageAttachment/_shared/DownloadAction.test.tsx +8 -5
- package/src/components/MessageAttachment/_shared/ImageViewer.test.tsx +6 -3
- package/src/components/MessageAttachment/_shared/MediaStackGrid.test.tsx +11 -4
- package/src/components/MessageAttachment/_shared/PdfViewer.test.tsx +5 -3
- package/src/components/MessageAttachment/_shared/VideoViewer.test.tsx +12 -3
- package/src/components/MessageAttachment/_shared/ViewerShell.test.tsx +13 -6
- package/src/components/MessageAttachment/_shared/useCarousel.test.tsx +10 -4
- package/src/components/MessageAttachment/_shared/useIsClient.ts +23 -0
- package/src/components/MessageAttachment/index.tsx +25 -9
- package/src/components/MessageAttachment/types.ts +19 -9
- package/src/components/MessageBubble/MessageBubble.test.tsx +8 -0
- package/src/components/RichCard/RichCard.test.tsx +10 -2
- package/src/styles.css +120 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linktr.ee/messaging-react",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0-rc-1788297811",
|
|
4
4
|
"description": "React messaging components built on messaging-core for web applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"chromatic:local": "yarn storybook:build && chromatic"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@linktr.ee/messaging-core": "
|
|
54
|
-
"@linktr.ee/messaging-taxonomy": "
|
|
53
|
+
"@linktr.ee/messaging-core": "2.6.0-rc-1788297811",
|
|
54
|
+
"@linktr.ee/messaging-taxonomy": "0.11.0-rc-1788297811",
|
|
55
55
|
"@phosphor-icons/react": "^2.1.10"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
renderWithProviders,
|
|
7
7
|
screen,
|
|
8
8
|
waitFor,
|
|
9
|
+
userEvent,
|
|
9
10
|
} from '../../test/utils'
|
|
10
11
|
|
|
11
12
|
import MediaPlayer from './MediaPlayer'
|
|
@@ -119,6 +120,7 @@ describe('MediaPlayer', () => {
|
|
|
119
120
|
})
|
|
120
121
|
|
|
121
122
|
it('shows a manual play overlay after rejected playback and starts from a gesture', async () => {
|
|
123
|
+
const user = userEvent.setup()
|
|
122
124
|
const play = vi.mocked(HTMLMediaElement.prototype.play)
|
|
123
125
|
play.mockRejectedValueOnce(new Error('autoplay blocked'))
|
|
124
126
|
const onContainerClick = vi.fn()
|
|
@@ -135,22 +137,23 @@ describe('MediaPlayer', () => {
|
|
|
135
137
|
|
|
136
138
|
const overlay = await screen.findByRole('button', { name: 'Play preview' })
|
|
137
139
|
expect(play).toHaveBeenCalledTimes(1)
|
|
138
|
-
|
|
140
|
+
await user.click(overlay)
|
|
139
141
|
await waitFor(() => expect(play).toHaveBeenCalledTimes(2))
|
|
140
142
|
expect(onContainerClick).not.toHaveBeenCalled()
|
|
141
143
|
expect(screen.queryByRole('button', { name: 'Play preview' })).toBeNull()
|
|
142
144
|
})
|
|
143
145
|
|
|
144
146
|
it('toggles from the container only with controls, while an override owns the click', async () => {
|
|
147
|
+
const user = userEvent.setup()
|
|
145
148
|
const play = vi.mocked(HTMLMediaElement.prototype.play)
|
|
146
149
|
const { rerender } = renderWithProviders(
|
|
147
150
|
<MediaPlayer source={SOURCE} mimeType="video/mp4" controls />
|
|
148
151
|
)
|
|
149
152
|
const root = screen.getByTestId('media-player')
|
|
150
153
|
|
|
151
|
-
|
|
154
|
+
await user.click(root)
|
|
152
155
|
await screen.findByRole('button', { name: 'Pause' })
|
|
153
|
-
|
|
156
|
+
await user.click(root)
|
|
154
157
|
await screen.findByRole('button', { name: 'Play' })
|
|
155
158
|
expect(play).toHaveBeenCalledTimes(1)
|
|
156
159
|
|
|
@@ -163,7 +166,7 @@ describe('MediaPlayer', () => {
|
|
|
163
166
|
onContainerClick={onContainerClick}
|
|
164
167
|
/>
|
|
165
168
|
)
|
|
166
|
-
|
|
169
|
+
await user.click(root)
|
|
167
170
|
expect(onContainerClick).toHaveBeenCalledTimes(1)
|
|
168
171
|
expect(screen.getByRole('button', { name: 'Play' })).toBeInTheDocument()
|
|
169
172
|
fireEvent.keyDown(root, { key: 'Enter' })
|
|
@@ -206,11 +209,12 @@ describe('MediaPlayer', () => {
|
|
|
206
209
|
})
|
|
207
210
|
|
|
208
211
|
it('does not let the controls button bubble into the container toggle', async () => {
|
|
212
|
+
const user = userEvent.setup()
|
|
209
213
|
renderWithProviders(
|
|
210
214
|
<MediaPlayer source={SOURCE} mimeType="video/mp4" controls />
|
|
211
215
|
)
|
|
212
216
|
|
|
213
|
-
|
|
217
|
+
await user.click(screen.getByRole('button', { name: 'Play' }))
|
|
214
218
|
await screen.findByRole('button', { name: 'Pause' })
|
|
215
219
|
})
|
|
216
220
|
|
|
@@ -91,6 +91,7 @@ describe('AttachmentThumbnail', () => {
|
|
|
91
91
|
expect(image).toHaveClass('opacity-0')
|
|
92
92
|
fireEvent.load(image)
|
|
93
93
|
expect(image).toHaveClass('opacity-100')
|
|
94
|
+
// eslint-disable-next-line testing-library/no-node-access -- the component shell wrapper has no semantic query.
|
|
94
95
|
expect(container.firstElementChild).toHaveClass('aspect-video')
|
|
95
96
|
})
|
|
96
97
|
|
|
@@ -126,6 +127,7 @@ describe('AttachmentThumbnail', () => {
|
|
|
126
127
|
expect(contained).toHaveClass('opacity-0')
|
|
127
128
|
fireEvent.load(contained)
|
|
128
129
|
expect(contained).toHaveClass('opacity-100')
|
|
130
|
+
// eslint-disable-next-line testing-library/no-node-access -- the component shell wrapper has no semantic query.
|
|
129
131
|
expect(container.firstElementChild).toHaveClass('aspect-video')
|
|
130
132
|
|
|
131
133
|
rerender(
|
|
@@ -170,6 +172,7 @@ describe('AttachmentThumbnail', () => {
|
|
|
170
172
|
)
|
|
171
173
|
const darkImage = screen.getByRole('img', { name: 'Poster' })
|
|
172
174
|
expect(darkImage).toHaveAttribute('src', OPTIMIZED_THUMBNAIL)
|
|
175
|
+
// eslint-disable-next-line testing-library/no-node-access -- the component shell wrapper has no semantic query.
|
|
173
176
|
expect(view.container.firstElementChild).toHaveClass(
|
|
174
177
|
'aspect-video',
|
|
175
178
|
'bg-white/10'
|
|
@@ -186,6 +189,7 @@ describe('AttachmentThumbnail', () => {
|
|
|
186
189
|
/>
|
|
187
190
|
)
|
|
188
191
|
expect(screen.getByRole('img')).toHaveAttribute('alt', '')
|
|
192
|
+
// eslint-disable-next-line testing-library/no-node-access -- the component shell wrapper has no semantic query.
|
|
189
193
|
expect(view.container.firstElementChild).toHaveClass(
|
|
190
194
|
'aspect-video',
|
|
191
195
|
'bg-black/5'
|
|
@@ -86,8 +86,10 @@ const defaultProps = () => ({
|
|
|
86
86
|
participant: createParticipant(),
|
|
87
87
|
})
|
|
88
88
|
|
|
89
|
-
const openMenu = async () =>
|
|
90
|
-
userEvent.
|
|
89
|
+
const openMenu = async () => {
|
|
90
|
+
const user = userEvent.setup()
|
|
91
|
+
await user.click(screen.getByRole('button', { name: 'More options' }))
|
|
92
|
+
}
|
|
91
93
|
|
|
92
94
|
describe('ChannelActionsMenu', () => {
|
|
93
95
|
beforeEach(() => {
|
|
@@ -125,12 +127,13 @@ describe('ChannelActionsMenu', () => {
|
|
|
125
127
|
})
|
|
126
128
|
|
|
127
129
|
it('closes the popover when Escape is pressed', async () => {
|
|
130
|
+
const user = userEvent.setup()
|
|
128
131
|
renderWithProviders(<ChannelActionsMenu {...defaultProps()} />)
|
|
129
132
|
|
|
130
133
|
await openMenu()
|
|
131
134
|
expect(screen.getByText('Report')).toBeInTheDocument()
|
|
132
135
|
|
|
133
|
-
await
|
|
136
|
+
await user.keyboard('{Escape}')
|
|
134
137
|
|
|
135
138
|
await waitFor(() => {
|
|
136
139
|
expect(screen.queryByText('Report')).not.toBeInTheDocument()
|
|
@@ -138,6 +141,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
138
141
|
})
|
|
139
142
|
|
|
140
143
|
it('closes the popover when clicking outside', async () => {
|
|
144
|
+
const user = userEvent.setup()
|
|
141
145
|
renderWithProviders(
|
|
142
146
|
<div>
|
|
143
147
|
<span data-testid="outside">outside</span>
|
|
@@ -148,7 +152,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
148
152
|
await openMenu()
|
|
149
153
|
expect(screen.getByText('Report')).toBeInTheDocument()
|
|
150
154
|
|
|
151
|
-
await
|
|
155
|
+
await user.click(screen.getByTestId('outside'))
|
|
152
156
|
|
|
153
157
|
await waitFor(() => {
|
|
154
158
|
expect(screen.queryByText('Report')).not.toBeInTheDocument()
|
|
@@ -156,6 +160,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
156
160
|
})
|
|
157
161
|
|
|
158
162
|
it('calls onDeleteConversationClick and closes after deleting', async () => {
|
|
163
|
+
const user = userEvent.setup()
|
|
159
164
|
const onDeleteConversationClick = vi.fn()
|
|
160
165
|
renderWithProviders(
|
|
161
166
|
<ChannelActionsMenu
|
|
@@ -165,7 +170,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
165
170
|
)
|
|
166
171
|
|
|
167
172
|
await openMenu()
|
|
168
|
-
await
|
|
173
|
+
await user.click(screen.getByText('Delete Conversation'))
|
|
169
174
|
|
|
170
175
|
await waitFor(() => {
|
|
171
176
|
expect(onDeleteConversationClick).toHaveBeenCalledOnce()
|
|
@@ -176,6 +181,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
176
181
|
})
|
|
177
182
|
|
|
178
183
|
it('calls onBlockParticipantClick and blocks the user', async () => {
|
|
184
|
+
const user = userEvent.setup()
|
|
179
185
|
const onBlockParticipantClick = vi.fn()
|
|
180
186
|
renderWithProviders(
|
|
181
187
|
<ChannelActionsMenu
|
|
@@ -185,7 +191,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
185
191
|
)
|
|
186
192
|
|
|
187
193
|
await openMenu()
|
|
188
|
-
await
|
|
194
|
+
await user.click(screen.getByText('Block'))
|
|
189
195
|
|
|
190
196
|
await waitFor(() => {
|
|
191
197
|
expect(onBlockParticipantClick).toHaveBeenCalledOnce()
|
|
@@ -206,6 +212,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
206
212
|
})
|
|
207
213
|
|
|
208
214
|
it('disables the block action until the blocked-status lookup resolves', async () => {
|
|
215
|
+
const user = userEvent.setup()
|
|
209
216
|
let resolveBlockedUsers: (
|
|
210
217
|
value: Array<{ blocked_user_id: string }>
|
|
211
218
|
) => void = () => {}
|
|
@@ -221,9 +228,9 @@ describe('ChannelActionsMenu', () => {
|
|
|
221
228
|
|
|
222
229
|
// While the lookup is pending the action is disabled so a premature click
|
|
223
230
|
// can't act on a stale block state.
|
|
224
|
-
const pendingBlock = screen.
|
|
231
|
+
const pendingBlock = screen.getByRole('button', { name: 'Block' })
|
|
225
232
|
expect(pendingBlock).toBeDisabled()
|
|
226
|
-
await
|
|
233
|
+
await user.click(pendingBlock)
|
|
227
234
|
expect(blockUserMock).not.toHaveBeenCalled()
|
|
228
235
|
|
|
229
236
|
// Once the lookup resolves (already blocked) the Unblock action is offered.
|
|
@@ -247,7 +254,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
247
254
|
// The lookup rejected, but the action recovers — Block becomes actionable
|
|
248
255
|
// rather than staying stuck in the disabled spinner state.
|
|
249
256
|
await waitFor(() => {
|
|
250
|
-
const block = screen.
|
|
257
|
+
const block = screen.getByRole('button', { name: 'Block' })
|
|
251
258
|
expect(block).not.toBeDisabled()
|
|
252
259
|
})
|
|
253
260
|
|
|
@@ -255,6 +262,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
255
262
|
})
|
|
256
263
|
|
|
257
264
|
it('calls onReportParticipantClick and opens the report page', async () => {
|
|
265
|
+
const user = userEvent.setup()
|
|
258
266
|
const onReportParticipantClick = vi.fn()
|
|
259
267
|
const windowOpenSpy = vi
|
|
260
268
|
.spyOn(window, 'open')
|
|
@@ -267,7 +275,7 @@ describe('ChannelActionsMenu', () => {
|
|
|
267
275
|
)
|
|
268
276
|
|
|
269
277
|
await openMenu()
|
|
270
|
-
await
|
|
278
|
+
await user.click(screen.getByText('Report'))
|
|
271
279
|
|
|
272
280
|
await waitFor(() => {
|
|
273
281
|
expect(onReportParticipantClick).toHaveBeenCalledOnce()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Channel } from 'stream-chat'
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { userEvent, renderWithProviders, screen } from '../../test/utils'
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
ChannelListProvider,
|
|
@@ -36,7 +36,8 @@ function ContextConsumer() {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
describe('ChannelListContext', () => {
|
|
39
|
-
it('provides safe documented defaults without a provider', () => {
|
|
39
|
+
it('provides safe documented defaults without a provider', async () => {
|
|
40
|
+
const user = userEvent.setup()
|
|
40
41
|
renderWithProviders(<ContextConsumer />)
|
|
41
42
|
|
|
42
43
|
expect(screen.getByTestId('selected-channel')).toHaveTextContent(
|
|
@@ -48,10 +49,11 @@ describe('ChannelListContext', () => {
|
|
|
48
49
|
)
|
|
49
50
|
expect(screen.getByTestId('channel-preview')).toHaveTextContent('undefined')
|
|
50
51
|
expect(screen.getByTestId('viewer-language')).toHaveTextContent('undefined')
|
|
51
|
-
|
|
52
|
+
await user.click(screen.getByRole('button'))
|
|
52
53
|
})
|
|
53
54
|
|
|
54
|
-
it('exposes the value supplied by a provider', () => {
|
|
55
|
+
it('exposes the value supplied by a provider', async () => {
|
|
56
|
+
const user = userEvent.setup()
|
|
55
57
|
const onChannelSelect = vi.fn()
|
|
56
58
|
const ChannelPreview = () => null
|
|
57
59
|
const renderMessagePreview = () => 'preview'
|
|
@@ -81,7 +83,7 @@ describe('ChannelListContext', () => {
|
|
|
81
83
|
expect(screen.getByTestId('channel-preview')).toHaveTextContent('provided')
|
|
82
84
|
expect(screen.getByTestId('viewer-language')).toHaveTextContent('es')
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
await user.click(screen.getByRole('button'))
|
|
85
87
|
expect(onChannelSelect).toHaveBeenCalledWith(channel)
|
|
86
88
|
})
|
|
87
89
|
})
|
|
@@ -3,7 +3,7 @@ import { act, createEvent, fireEvent } from '@testing-library/react'
|
|
|
3
3
|
import { Channel, LocalMessage, StreamChat } from 'stream-chat'
|
|
4
4
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
5
|
|
|
6
|
-
import { renderWithProviders, screen } from '../../test/utils'
|
|
6
|
+
import { userEvent, renderWithProviders, screen } from '../../test/utils'
|
|
7
7
|
import type { ChannelPreviewProps } from '../../types'
|
|
8
8
|
|
|
9
9
|
import { ChannelListProvider } from './ChannelListContext'
|
|
@@ -136,7 +136,8 @@ describe('CustomChannelPreview', () => {
|
|
|
136
136
|
expect(screen.getByRole('button')).toHaveClass('hover:bg-black/[0.02]')
|
|
137
137
|
})
|
|
138
138
|
|
|
139
|
-
it('selects the channel by click and activation keys only', () => {
|
|
139
|
+
it('selects the channel by click and activation keys only', async () => {
|
|
140
|
+
const user = userEvent.setup()
|
|
140
141
|
const channel = createMockChannel([])
|
|
141
142
|
const onChannelSelect = vi.fn()
|
|
142
143
|
renderWithProviders(
|
|
@@ -146,7 +147,7 @@ describe('CustomChannelPreview', () => {
|
|
|
146
147
|
)
|
|
147
148
|
const row = screen.getByRole('button')
|
|
148
149
|
|
|
149
|
-
|
|
150
|
+
await user.click(row)
|
|
150
151
|
fireEvent.keyDown(row, { key: 'Enter' })
|
|
151
152
|
const spaceEvent = createEvent.keyDown(row, { key: ' ' })
|
|
152
153
|
fireEvent(row, spaceEvent)
|
|
@@ -782,7 +783,8 @@ describe('CustomChannelPreview', () => {
|
|
|
782
783
|
).toBeInTheDocument()
|
|
783
784
|
})
|
|
784
785
|
|
|
785
|
-
it('renders a custom channel preview with selection props from context', () => {
|
|
786
|
+
it('renders a custom channel preview with selection props from context', async () => {
|
|
787
|
+
const user = userEvent.setup()
|
|
786
788
|
const channel = createMockChannel([])
|
|
787
789
|
const onChannelSelect = vi.fn()
|
|
788
790
|
const ChannelPreview = vi.fn(
|
|
@@ -818,7 +820,7 @@ describe('CustomChannelPreview', () => {
|
|
|
818
820
|
</ChannelListProvider>
|
|
819
821
|
)
|
|
820
822
|
|
|
821
|
-
|
|
823
|
+
await user.click(
|
|
822
824
|
screen.getByRole('button', { name: 'Selected channel-1 es active' })
|
|
823
825
|
)
|
|
824
826
|
|
|
@@ -318,6 +318,7 @@ describe('ChannelList', () => {
|
|
|
318
318
|
/>
|
|
319
319
|
)
|
|
320
320
|
|
|
321
|
+
// eslint-disable-next-line testing-library/no-node-access -- the component shell wrapper has no semantic query.
|
|
321
322
|
expect(container.firstElementChild).toHaveClass(
|
|
322
323
|
'messaging-channel-list',
|
|
323
324
|
'h-full',
|
|
@@ -3,7 +3,7 @@ import React from 'react'
|
|
|
3
3
|
import type { Channel } from 'stream-chat'
|
|
4
4
|
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
5
5
|
|
|
6
|
-
import { renderWithProviders, screen, within } from '../test/utils'
|
|
6
|
+
import { renderWithProviders, screen, userEvent, within } from '../test/utils'
|
|
7
7
|
|
|
8
8
|
import { ChannelView } from './ChannelView'
|
|
9
9
|
|
|
@@ -266,7 +266,8 @@ describe('ChannelView', () => {
|
|
|
266
266
|
expect(screen.getByTestId('channel-actions-menu')).toBeInTheDocument()
|
|
267
267
|
})
|
|
268
268
|
|
|
269
|
-
it('renders the redesigned header button when onParticipantNameClick is provided', () => {
|
|
269
|
+
it('renders the redesigned header button when onParticipantNameClick is provided', async () => {
|
|
270
|
+
const user = userEvent.setup()
|
|
270
271
|
const onParticipantNameClick = vi.fn()
|
|
271
272
|
renderWithProviders(
|
|
272
273
|
<ChannelView
|
|
@@ -284,7 +285,7 @@ describe('ChannelView', () => {
|
|
|
284
285
|
expect(button).toContainElement(avatars[0])
|
|
285
286
|
expect(screen.getByTestId('channel-actions-menu')).toBeInTheDocument()
|
|
286
287
|
|
|
287
|
-
|
|
288
|
+
await user.click(button)
|
|
288
289
|
expect(onParticipantNameClick).toHaveBeenCalledTimes(1)
|
|
289
290
|
})
|
|
290
291
|
|
|
@@ -357,7 +358,8 @@ describe('ChannelView', () => {
|
|
|
357
358
|
)
|
|
358
359
|
})
|
|
359
360
|
|
|
360
|
-
it('keeps message rows mounted while updating the outbound click handler', () => {
|
|
361
|
+
it('keeps message rows mounted while updating the outbound click handler', async () => {
|
|
362
|
+
const user = userEvent.setup()
|
|
361
363
|
const firstHandler = vi.fn()
|
|
362
364
|
const secondHandler = vi.fn()
|
|
363
365
|
const { rerender: rerenderChannel } = renderWithProviders(
|
|
@@ -387,7 +389,7 @@ describe('ChannelView', () => {
|
|
|
387
389
|
expect(customMessageMounts).toHaveBeenCalledOnce()
|
|
388
390
|
expect(customMessageUnmounts).not.toHaveBeenCalled()
|
|
389
391
|
|
|
390
|
-
screen.getByTestId('custom-message')
|
|
392
|
+
await user.click(screen.getByTestId('custom-message'))
|
|
391
393
|
expect(firstHandler).not.toHaveBeenCalled()
|
|
392
394
|
expect(secondHandler).toHaveBeenCalledWith({
|
|
393
395
|
id: 'automation-1',
|
|
@@ -443,14 +445,15 @@ describe('ChannelView', () => {
|
|
|
443
445
|
|
|
444
446
|
expect(renderConversationFooter).toHaveBeenCalledWith(channel)
|
|
445
447
|
expect(conversationFooter).toHaveTextContent('footer-channel-1')
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
).
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
448
|
+
const regions = screen.getAllByTestId(
|
|
449
|
+
/message-list|conversation-footer|message-input/
|
|
450
|
+
)
|
|
451
|
+
expect(regions.indexOf(messageList)).toBeLessThan(
|
|
452
|
+
regions.indexOf(conversationFooter)
|
|
453
|
+
)
|
|
454
|
+
expect(regions.indexOf(conversationFooter)).toBeLessThan(
|
|
455
|
+
regions.indexOf(messageInput)
|
|
456
|
+
)
|
|
454
457
|
})
|
|
455
458
|
|
|
456
459
|
it('keeps conversation footer inside the floating composer via renderHeader', () => {
|
|
@@ -567,9 +570,11 @@ describe('ChannelView', () => {
|
|
|
567
570
|
)
|
|
568
571
|
|
|
569
572
|
expect(
|
|
573
|
+
// eslint-disable-next-line testing-library/no-node-access -- these class selectors verify responsive back-button styling with no semantic query.
|
|
570
574
|
document.querySelectorAll('.messaging-channel-view-back-button-mobile')
|
|
571
575
|
).toHaveLength(1)
|
|
572
576
|
expect(
|
|
577
|
+
// eslint-disable-next-line testing-library/no-node-access -- these class selectors verify responsive back-button styling with no semantic query.
|
|
573
578
|
document.querySelectorAll('.messaging-channel-view-back-button-desktop')
|
|
574
579
|
).toHaveLength(1)
|
|
575
580
|
})
|
|
@@ -584,9 +589,11 @@ describe('ChannelView', () => {
|
|
|
584
589
|
)
|
|
585
590
|
|
|
586
591
|
expect(
|
|
592
|
+
// eslint-disable-next-line testing-library/no-node-access -- these class selectors verify responsive back-button styling with no semantic query.
|
|
587
593
|
document.querySelectorAll('.messaging-channel-view-back-button-mobile')
|
|
588
594
|
).toHaveLength(0)
|
|
589
595
|
expect(
|
|
596
|
+
// eslint-disable-next-line testing-library/no-node-access -- these class selectors verify responsive back-button styling with no semantic query.
|
|
590
597
|
document.querySelectorAll('.messaging-channel-view-back-button-desktop')
|
|
591
598
|
).toHaveLength(0)
|
|
592
599
|
})
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import { LinkPreview, LinkPreviewStatus } from 'stream-chat'
|
|
3
3
|
import { describe, expect, it, vi } from 'vitest'
|
|
4
4
|
|
|
5
|
-
import { renderWithProviders, screen
|
|
5
|
+
import { userEvent, renderWithProviders, screen } from '../../test/utils'
|
|
6
6
|
import { LOADING_LABEL } from '../LinkAttachment/components/_shared/CardShell'
|
|
7
7
|
|
|
8
8
|
import { CustomLinkPreviewList } from '.'
|
|
@@ -82,7 +82,8 @@ describe('CustomLinkPreviewList', () => {
|
|
|
82
82
|
expect(list).not.toHaveClass('min-h-0')
|
|
83
83
|
})
|
|
84
84
|
|
|
85
|
-
it('is dismiss-only: the staged card never navigates', () => {
|
|
85
|
+
it('is dismiss-only: the staged card never navigates', async () => {
|
|
86
|
+
const user = userEvent.setup()
|
|
86
87
|
// The deliberate behaviour change in MES-1349 — see this component's own
|
|
87
88
|
// doc comment for why (MES-1358 §7 Q7, touch hazard). Asserted so the
|
|
88
89
|
// anchor cannot be reinstated by accident.
|
|
@@ -97,7 +98,7 @@ describe('CustomLinkPreviewList', () => {
|
|
|
97
98
|
expect(controls).toHaveLength(1)
|
|
98
99
|
expect(controls[0]).toHaveAttribute('aria-label', 'Dismiss attachment')
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
await user.click(controls[0])
|
|
101
102
|
expect(dismissPreview).toHaveBeenCalledWith('https://example.com/story')
|
|
102
103
|
})
|
|
103
104
|
})
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import { useChannelStateContext, useMessageContext } from 'stream-chat-react'
|
|
3
3
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
4
4
|
|
|
5
|
-
import { renderWithProviders, screen } from '../../test/utils'
|
|
5
|
+
import { renderWithProviders, screen, userEvent } from '../../test/utils'
|
|
6
6
|
|
|
7
7
|
import { OutboundContext } from './OutboundContext'
|
|
8
8
|
import { isTipMessage } from './TipMessage'
|
|
@@ -147,7 +147,8 @@ describe('CustomMessage', () => {
|
|
|
147
147
|
} as never)
|
|
148
148
|
})
|
|
149
149
|
|
|
150
|
-
it('uses the latest outbound click handler after rerendering', () => {
|
|
150
|
+
it('uses the latest outbound click handler after rerendering', async () => {
|
|
151
|
+
const user = userEvent.setup()
|
|
151
152
|
const firstHandler = vi.fn()
|
|
152
153
|
const secondHandler = vi.fn()
|
|
153
154
|
const { rerender } = renderWithProviders(
|
|
@@ -175,11 +176,11 @@ describe('CustomMessage', () => {
|
|
|
175
176
|
<CustomMessage onOutboundClick={secondHandler} />
|
|
176
177
|
</OutboundContext.Provider>
|
|
177
178
|
)
|
|
178
|
-
|
|
179
|
-
.getByRole('button', {
|
|
179
|
+
await user.click(
|
|
180
|
+
screen.getByRole('button', {
|
|
180
181
|
name: 'View broadcast July 9th Class attendees',
|
|
181
182
|
})
|
|
182
|
-
|
|
183
|
+
)
|
|
183
184
|
|
|
184
185
|
expect(firstHandler).not.toHaveBeenCalled()
|
|
185
186
|
expect(secondHandler).toHaveBeenCalledWith({
|
|
@@ -37,6 +37,7 @@ describe('MessageTag', () => {
|
|
|
37
37
|
expect(indicator).toHaveTextContent('Sent by AI Assistant')
|
|
38
38
|
|
|
39
39
|
// icon first, then label
|
|
40
|
+
// eslint-disable-next-line testing-library/no-node-access -- media or rendered-markup internals have no user-facing query.
|
|
40
41
|
expect(indicator.children[0].querySelector('svg')).not.toBeNull()
|
|
41
42
|
expect(indicator.children[1]).toHaveTextContent('Sent by AI Assistant')
|
|
42
43
|
})
|
|
@@ -56,6 +57,7 @@ describe('MessageTag', () => {
|
|
|
56
57
|
|
|
57
58
|
// label first, then icon (mirrored)
|
|
58
59
|
expect(indicator.children[0]).toHaveTextContent('Sent by AI Assistant')
|
|
60
|
+
// eslint-disable-next-line testing-library/no-node-access -- media or rendered-markup internals have no user-facing query.
|
|
59
61
|
expect(indicator.children[1].querySelector('svg')).not.toBeNull()
|
|
60
62
|
})
|
|
61
63
|
|
|
@@ -74,6 +76,7 @@ describe('MessageTag', () => {
|
|
|
74
76
|
expect(indicator).toHaveTextContent('Sent with AI')
|
|
75
77
|
|
|
76
78
|
// icon first, then label
|
|
79
|
+
// eslint-disable-next-line testing-library/no-node-access -- media or rendered-markup internals have no user-facing query.
|
|
77
80
|
expect(indicator.children[0].querySelector('svg')).not.toBeNull()
|
|
78
81
|
expect(indicator.children[1]).toHaveTextContent('Sent with AI')
|
|
79
82
|
})
|
|
@@ -88,6 +91,7 @@ describe('MessageTag', () => {
|
|
|
88
91
|
)
|
|
89
92
|
|
|
90
93
|
const paidTag = screen.getByText('Delivered with $10.00 message')
|
|
94
|
+
// eslint-disable-next-line testing-library/no-node-access -- the component wrapper class has no semantic query.
|
|
91
95
|
expect(paidTag.closest('.message-tag--paid')).not.toBeNull()
|
|
92
96
|
})
|
|
93
97
|
|
|
@@ -100,6 +104,7 @@ describe('MessageTag', () => {
|
|
|
100
104
|
/>
|
|
101
105
|
)
|
|
102
106
|
|
|
107
|
+
// eslint-disable-next-line testing-library/no-node-access -- the null-rendering DOM contract has no semantic query.
|
|
103
108
|
expect(container.firstChild).toBeNull()
|
|
104
109
|
})
|
|
105
110
|
|
|
@@ -108,6 +113,7 @@ describe('MessageTag', () => {
|
|
|
108
113
|
<MessageTag message={createMockMessage()} />
|
|
109
114
|
)
|
|
110
115
|
|
|
116
|
+
// eslint-disable-next-line testing-library/no-node-access -- the null-rendering DOM contract has no semantic query.
|
|
111
117
|
expect(container.firstChild).toBeNull()
|
|
112
118
|
})
|
|
113
119
|
})
|
|
@@ -2,7 +2,12 @@ import React from 'react'
|
|
|
2
2
|
import { useChannelStateContext, useMessageContext } from 'stream-chat-react'
|
|
3
3
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
renderWithProviders,
|
|
7
|
+
screen,
|
|
8
|
+
userEvent,
|
|
9
|
+
within,
|
|
10
|
+
} from '../../test/utils'
|
|
6
11
|
|
|
7
12
|
import { SentMessageDeliveryStatus } from './SentMessageDeliveryStatus'
|
|
8
13
|
|
|
@@ -232,9 +237,11 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
232
237
|
name: 'View broadcast Broadcast',
|
|
233
238
|
})
|
|
234
239
|
expect(
|
|
240
|
+
// eslint-disable-next-line testing-library/no-node-access -- media or rendered-markup internals have no user-facing query.
|
|
235
241
|
button.querySelector('.sent-message-outbound-badge')
|
|
236
242
|
).toBeInTheDocument()
|
|
237
243
|
expect(
|
|
244
|
+
// eslint-disable-next-line testing-library/no-node-access -- media or rendered-markup internals have no user-facing query.
|
|
238
245
|
button.querySelector('.sent-message-outbound-name')
|
|
239
246
|
).toHaveTextContent('Broadcast')
|
|
240
247
|
expect(button).not.toHaveTextContent('•')
|
|
@@ -275,6 +282,7 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
275
282
|
expect(button).not.toHaveTextContent('•')
|
|
276
283
|
expect(name).toHaveClass('sent-message-outbound-name')
|
|
277
284
|
expect(
|
|
285
|
+
// eslint-disable-next-line testing-library/no-node-access -- media or rendered-markup internals have no user-facing query.
|
|
278
286
|
button.querySelector('.sent-message-outbound-badge')
|
|
279
287
|
).toHaveAttribute('aria-hidden', 'true')
|
|
280
288
|
expect(screen.getAllByTestId('sent-message-delivery-status')).toHaveLength(
|
|
@@ -282,7 +290,8 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
282
290
|
)
|
|
283
291
|
})
|
|
284
292
|
|
|
285
|
-
it('passes the resolved outbound name to the click callback', () => {
|
|
293
|
+
it('passes the resolved outbound name to the click callback', async () => {
|
|
294
|
+
const user = userEvent.setup()
|
|
286
295
|
const onOutboundClick = vi.fn()
|
|
287
296
|
mockedUseMessageContext.mockReturnValue({
|
|
288
297
|
message: {
|
|
@@ -305,11 +314,11 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
305
314
|
/>
|
|
306
315
|
)
|
|
307
316
|
|
|
308
|
-
|
|
309
|
-
.getByRole('button', {
|
|
317
|
+
await user.click(
|
|
318
|
+
screen.getByRole('button', {
|
|
310
319
|
name: 'View broadcast July 9th Class absentee',
|
|
311
320
|
})
|
|
312
|
-
|
|
321
|
+
)
|
|
313
322
|
|
|
314
323
|
expect(onOutboundClick).toHaveBeenCalledWith({
|
|
315
324
|
id: 'automation-1',
|
|
@@ -317,7 +326,8 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
317
326
|
})
|
|
318
327
|
})
|
|
319
328
|
|
|
320
|
-
it('reports a campaign named Broadcast on click', () => {
|
|
329
|
+
it('reports a campaign named Broadcast on click', async () => {
|
|
330
|
+
const user = userEvent.setup()
|
|
321
331
|
const onOutboundClick = vi.fn()
|
|
322
332
|
mockedUseMessageContext.mockReturnValue({
|
|
323
333
|
message: {
|
|
@@ -337,11 +347,11 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
337
347
|
/>
|
|
338
348
|
)
|
|
339
349
|
|
|
340
|
-
|
|
341
|
-
.getByRole('button', {
|
|
350
|
+
await user.click(
|
|
351
|
+
screen.getByRole('button', {
|
|
342
352
|
name: 'View broadcast Broadcast',
|
|
343
353
|
})
|
|
344
|
-
|
|
354
|
+
)
|
|
345
355
|
|
|
346
356
|
expect(onOutboundClick).toHaveBeenCalledWith({
|
|
347
357
|
id: 'automation-1',
|