Skip to content

Commit

Permalink
feat: extract CardAudio and render only uploaded audio data in Audio …
Browse files Browse the repository at this point in the history
…component
  • Loading branch information
MartinCupela committed Jul 8, 2022
1 parent 0f42f62 commit 8027908
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 88 deletions.
73 changes: 41 additions & 32 deletions src/components/Attachment/Audio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import React from 'react';
import type { Attachment } from 'stream-chat';

import { PauseIcon, PlayTriangleIcon } from './icons';
import { isScrapedContent } from './utils';

import { FileSizeIndicator } from './FileSizeIndicator';
import { DownloadButton } from './DownloadButton';
Expand Down Expand Up @@ -108,13 +107,50 @@ const ProgressBar = ({ progress }: ProgressBarProps) => (
</div>
);

export const CardAudio = ({ og: { asset_url, text, title } }: AudioProps) => {
const { audioRef, isPlaying, progress, togglePlay } = useAudioController();

const dataTestId = 'card-audio-widget';
const rootClassName = 'str-chat__message-attachment-card-audio-widget';
return (
<div className={rootClassName} data-testid={dataTestId}>
{asset_url && (
<>
<audio ref={audioRef}>
<source data-testid='audio-source' src={asset_url} type='audio/mp3' />
</audio>
<div className='str-chat__message-attachment-card-audio-widget--first-row'>
<div className='str-chat__message-attachment-audio-widget--play-controls'>
<PlayButton isPlaying={isPlaying} onClick={togglePlay} />
</div>
<ProgressBar progress={progress} />
</div>
</>
)}
<div className='str-chat__message-attachment-audio-widget--second-row'>
{title && <div className='str-chat__message-attachment-audio-widget--title'>{title}</div>}
{text && (
<div className='str-chat__message-attachment-audio-widget--description'>{text}</div>
)}
</div>
</div>
);
};

const AudioV2 = ({ og }: AudioProps) => {
const { asset_url, file_size, text, title } = og;
const { asset_url, file_size, title } = og;
const { audioRef, isPlaying, progress, togglePlay } = useAudioController();

let rootClassName = 'str-chat__message-attachment-audio-widget';
let audioContent = (
<>
if (!asset_url) return null;

const dataTestId = 'audio-widget';
const rootClassName = 'str-chat__message-attachment-audio-widget';

return (
<div className={rootClassName} data-testid={dataTestId}>
<audio ref={audioRef}>
<source data-testid='audio-source' src={asset_url} type='audio/mp3' />
</audio>
<div className='str-chat__message-attachment-audio-widget--play-controls'>
<PlayButton isPlaying={isPlaying} onClick={togglePlay} />
</div>
Expand All @@ -128,33 +164,6 @@ const AudioV2 = ({ og }: AudioProps) => {
<ProgressBar progress={progress} />
</div>
</div>
</>
);

if (isScrapedContent(og)) {
rootClassName = 'str-chat__message-attachment-card-audio-widget';
audioContent = (
<>
<div className='str-chat__message-attachment-card-audio-widget--first-row'>
<div className='str-chat__message-attachment-audio-widget--play-controls'>
<PlayButton isPlaying={isPlaying} onClick={togglePlay} />
</div>
<ProgressBar progress={progress} />
</div>
<div className='str-chat__message-attachment-audio-widget--second-row'>
<div className='str-chat__message-attachment-audio-widget--title'>{title}</div>
<div className='str-chat__message-attachment-audio-widget--description'>{text}</div>
</div>
</>
);
}

return (
<div className={rootClassName}>
<audio ref={audioRef}>
<source data-testid='audio-source' src={asset_url} type='audio/mp3' />
</audio>
{audioContent}
</div>
);
};
Expand Down
70 changes: 15 additions & 55 deletions src/components/Attachment/__tests__/Audio.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,14 @@ import { Audio } from '../Audio';

import { ChatContext } from '../../../context/ChatContext';

import { generateAudioAttachment, generateScrapedAudioAttachment } from 'mock-builders';
import { generateAudioAttachment } from 'mock-builders';

const THEME_VERSIONS = ['1', '2'];

const AUDIO = {
scraped: generateScrapedAudioAttachment(),
uploaded: generateAudioAttachment(),
};
const AUDIO = generateAudioAttachment();

const renderComponent = (
props = {
chatContext: { themeVersion: '1' },
og: AUDIO.scraped,
og: AUDIO,
},
) =>
render(
Expand All @@ -40,74 +35,39 @@ describe('Audio', () => {
});
afterEach(cleanup);

it('in v1 scraped should render title and description as text, and render the image with description as alt tag', () => {
const audioData = AUDIO.scraped;
const { getByAltText, getByText } = renderComponent({
chatContext: { themeVersion: '1' },
og: audioData,
});

expect(getByText(audioData.title)).toBeInTheDocument();
expect(getByText(audioData.text)).toBeInTheDocument();

const image = getByAltText(audioData.description);
expect(image).toBeInTheDocument();
expect(image.src).toBe(audioData.image_url);
});

it('in v1 uploaded should render title and render the image with description as alt tag', () => {
const audioData = AUDIO.uploaded;
it('in v1 should render title and render the image with description as alt tag', () => {
const { container } = renderComponent({
chatContext: { themeVersion: '1' },
og: { ...audioData, title: 'deterministic' },
og: { ...AUDIO, title: 'deterministic' },
});

expect(container).toMatchSnapshot();
});

it('in v2 scraped should render title and description as text, and render the image with description as alt tag', () => {
const { container, getByText } = renderComponent({
chatContext: { themeVersion: '2' },
og: AUDIO.scraped,
});

expect(getByText(AUDIO.scraped.title)).toBeInTheDocument();
expect(getByText(AUDIO.scraped.text)).toBeInTheDocument();

expect(container.querySelector('img')).not.toBeInTheDocument();
});

it('in v2 uploaded should render title and file size', () => {
const { container, getByText } = renderComponent({
chatContext: { themeVersion: '2' },
og: AUDIO.uploaded,
og: AUDIO,
});

expect(getByText(AUDIO.uploaded.title)).toBeInTheDocument();
expect(getByText(prettybytes(AUDIO.uploaded.file_size))).toBeInTheDocument();
expect(getByText(AUDIO.title)).toBeInTheDocument();
expect(getByText(prettybytes(AUDIO.file_size))).toBeInTheDocument();
expect(container.querySelector('img')).not.toBeInTheDocument();
});

const matrix = THEME_VERSIONS.reduce((acc, version) => {
Object.entries(AUDIO).forEach(([type, attachment]) => {
acc.push([type, version, attachment]);
});
return acc;
}, []);

describe.each(matrix)('%s in version %s', (type, themeVersion, audioData) => {
describe.each([['1'], ['2']])('version %s', (themeVersion) => {
it('should render an audio element with the right source', () => {
const { getByTestId } = renderComponent({ chatContext: { themeVersion }, og: audioData });
const { getByTestId } = renderComponent({ chatContext: { themeVersion }, og: AUDIO });

const source = getByTestId('audio-source');

expect(source).toBeInTheDocument();
expect(source.src).toBe(audioData.asset_url);
expect(source.src).toBe(AUDIO.asset_url);
expect(source.parentElement).toBeInstanceOf(HTMLAudioElement);
});

it('should show the correct button if the song is paused/playing', async () => {
const { queryByTestId } = renderComponent({ chatContext: { themeVersion }, og: audioData });
const { queryByTestId } = renderComponent({ chatContext: { themeVersion }, og: AUDIO });

const playButton = () => queryByTestId(playButtonTestId);
const pauseButton = () => queryByTestId(pauseButtonTestId);
Expand All @@ -127,7 +87,7 @@ describe('Audio', () => {
});

it('should poll for progress every 500ms if the file is played, and stop doing that when it is paused', () => {
const { getByTestId } = renderComponent({ chatContext: { themeVersion }, og: audioData });
const { getByTestId } = renderComponent({ chatContext: { themeVersion }, og: AUDIO });

let intervalId;
const setIntervalSpy = jest.spyOn(window, 'setInterval').mockImplementationOnce(() => {
Expand All @@ -146,7 +106,7 @@ describe('Audio', () => {
it('should clean up the progress interval if the component is unmounted while the file is playing', () => {
const { getByTestId, unmount = cleanup } = renderComponent({
chatContext: { themeVersion },
og: audioData,
og: AUDIO,
});

let intervalId;
Expand All @@ -164,7 +124,7 @@ describe('Audio', () => {
});

it('should show the correct progress', async () => {
const { getByTestId } = renderComponent({ chatContext: { themeVersion }, og: audioData });
const { getByTestId } = renderComponent({ chatContext: { themeVersion }, og: AUDIO });

jest.spyOn(HTMLAudioElement.prototype, 'duration', 'get').mockImplementationOnce(() => 100);
jest.spyOn(HTMLAudioElement.prototype, 'currentTime', 'get').mockImplementationOnce(() => 50);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Audio in v1 uploaded should render title and render the image with description as alt tag 1`] = `
exports[`Audio in v1 should render title and render the image with description as alt tag 1`] = `
<div>
<div
class="str-chat__audio"
Expand Down

0 comments on commit 8027908

Please sign in to comment.