import React from 'react'
import type { Attachment, LocalMessage } from 'stream-chat'
import { describe, expect, it } from 'vitest'
import { fireEvent, renderWithProviders, screen } from '../../test/utils'
import StreamAttachmentMessage, {
linkCaptionDuplicatesAttachmentUrl,
linkCardPropsFromStreamAttachment,
} from './StreamAttachmentMessage'
const message = (attachments: Attachment[], text?: string): LocalMessage =>
({ attachments, text }) as LocalMessage
describe('linkCardPropsFromStreamAttachment', () => {
it('uses the featured layout when a thumbnail is present', () => {
expect(
linkCardPropsFromStreamAttachment({
type: 'link',
og_scrape_url: 'https://linktr.ee/someone',
image_url: 'https://cdn.example.com/thumb.jpg',
}).layout
).toBe('featured')
})
it('optimizes Linktree-hosted thumbnails for messaging attachment renders', () => {
expect(
linkCardPropsFromStreamAttachment({
type: 'link',
og_scrape_url: 'https://linktr.ee/someone',
image_url: 'https://assets.linktr.ee/thumb.jpg',
}).thumbnailUrl
).toBe(
'https://assets.linktr.ee/thumb.jpg?io=true&size=messaging-attachment-v1_0'
)
})
it('uses the classic layout for a plain link with no thumbnail', () => {
expect(
linkCardPropsFromStreamAttachment({
type: 'link',
og_scrape_url: 'https://linktr.ee/someone',
}).layout
).toBe('classic')
})
it('keeps the featured layout for a playable clip with no thumbnail so the player renders', () => {
expect(
linkCardPropsFromStreamAttachment({
type: 'link',
og_scrape_url: 'https://linktr.ee/someone',
asset_url: 'https://cdn.example.com/clip.mp3',
mime_type: 'audio/mpeg',
}).layout
).toBe('featured')
})
})
describe('linkCaptionDuplicatesAttachmentUrl', () => {
it('suppresses captions that are just the link plus punctuation', () => {
expect(
linkCaptionDuplicatesAttachmentUrl(
'https://tr.ee/abc !',
'https://tr.ee/abc'
)
).toBe(true)
})
it('keeps captions that add emoji after the link', () => {
expect(
linkCaptionDuplicatesAttachmentUrl(
'https://tr.ee/abc 😎',
'https://tr.ee/abc'
)
).toBe(false)
})
})
describe('StreamAttachmentMessage', () => {
it('renders a sent link card and suppresses a URL-only caption', () => {
renderWithProviders(
)
expect(screen.getByRole('link', { name: /my linktree/i })).toHaveAttribute(
'href',
'https://linktr.ee/someone'
)
expect(screen.queryByText('https://linktr.ee/someone !')).toBeNull()
})
it('keeps an emoji-only caption instead of dropping it', () => {
const { container } = renderWithProviders(
)
// MessageText linkifies the URL (display text drops the scheme), so the
// caption is split across a link node and trailing emoji text.
const captionBubble = container.querySelector(
'.str-chat__message-bubble:not([data-attachment-bubble])'
)
expect(captionBubble).toHaveTextContent('linktr.ee/someone')
expect(captionBubble).toHaveTextContent('😎')
})
it('renders mixed link and media attachments in order', () => {
const { container } = renderWithProviders(
)
const link = screen.getByRole('link', { name: /my linktree/i })
const imageBubble = screen.getByTestId('image-attachment')
expect(link.compareDocumentPosition(imageBubble)).toBe(
Node.DOCUMENT_POSITION_FOLLOWING
)
expect(container).toHaveTextContent('caption')
})
it('optimizes Linktree-hosted image attachments for the channel bubble', () => {
renderWithProviders(
)
expect(screen.getByRole('img', { name: 'Vacation' })).toHaveAttribute(
'src',
'https://ugc.production.linktr.ee/photo.jpg?io=true&size=messaging-attachment-v1_0'
)
})
it('optimizes Linktree-hosted video posters for the channel bubble', () => {
renderWithProviders(
)
// Video posters were the last media URL leaving here at full size —
// four of them per 2×2 grid.
expect(
screen.getByTestId('video-attachment').querySelector('img')
).toHaveAttribute(
'src',
'https://ugc.production.linktr.ee/poster.jpg?io=true&size=messaging-attachment-v1_0'
)
})
it('keeps the original image source in the viewer for channel image attachments', () => {
renderWithProviders(
)
fireEvent.click(screen.getByLabelText('Open image 1 of 1'))
const viewer = screen.getByTestId('image-viewer')
expect(viewer).toHaveAttribute('open')
expect(viewer.querySelector('img')?.getAttribute('src')).toBe(
'https://ugc.production.linktr.ee/photo.jpg'
)
})
it('renders the accompanying message text next to a link attachment', () => {
const { container } = renderWithProviders(
)
const bubbles = container.querySelectorAll('.str-chat__message-bubble')
expect(bubbles).toHaveLength(2)
expect(bubbles[0]).toHaveAttribute('data-attachment-bubble', 'true')
expect(bubbles[1]).toHaveTextContent('you have to see this')
})
it('renders the accompanying message text next to a media attachment', () => {
const { container } = renderWithProviders(
)
expect(container).toHaveTextContent('from the trip')
expect(
container.querySelector(
'.str-chat__message-bubble:not([data-attachment-bubble])'
)
).toHaveTextContent('from the trip')
})
})