diff --git a/packages/save-and-share-bar/src/save-and-share-bar.js b/packages/save-and-share-bar/src/save-and-share-bar.js index 7eab7605e2..7c4d84079e 100644 --- a/packages/save-and-share-bar/src/save-and-share-bar.js +++ b/packages/save-and-share-bar/src/save-and-share-bar.js @@ -8,7 +8,7 @@ import { } from "@times-components/icons"; import UserState from "@times-components/user-state"; import { SectionContext } from "@times-components/context"; -import { SaveStar } from "@times-components/ts-components"; +import { SaveStar, ArticleAudio } from "@times-components/ts-components"; import getTokenisedArticleUrlApi from "./get-tokenised-article-url-api"; import withTrackEvents from "./tracking/with-track-events"; @@ -247,6 +247,11 @@ function SaveAndShareBar(props) { )} ) : null} + {process.env.NODE_ENV !== "test" && ( +
+ +
+ )} ); } diff --git a/packages/ts-components/src/components/article-audio/ArticleAudio.tsx b/packages/ts-components/src/components/article-audio/ArticleAudio.tsx index 3ea2050baf..09d38b9284 100644 --- a/packages/ts-components/src/components/article-audio/ArticleAudio.tsx +++ b/packages/ts-components/src/components/article-audio/ArticleAudio.tsx @@ -1,5 +1,5 @@ import React, { FC, useState, useRef } from 'react'; -import { AudioButton } from './styles'; +import { AudioButton, AudioDuration } from './styles'; import { AudioPlayer } from '../audio-player-components/AudioPlayer'; import { PlayIcon, PauseIcon } from '@times-components/icons'; export interface ArticleAudioProps { @@ -30,6 +30,7 @@ export const ArticleAudio: FC = ({ audioSrc }) => { if (audioState === 'playing') { setAudioState('paused'); + setisAudioPlayerVisible(false); } else { setAudioState('playing'); } @@ -37,6 +38,7 @@ export const ArticleAudio: FC = ({ audioSrc }) => { const hidePlayer = () => { setisAudioPlayerVisible(false); + setAudioState('not-started'); }; return ( @@ -49,8 +51,9 @@ export const ArticleAudio: FC = ({ audioSrc }) => { /> @@ -67,25 +70,30 @@ export const ArticleAudio: FC = ({ audioSrc }) => { Listen )} - {' '} {duration} min - + - {isAudioPlayerVisible && ( +
setAudioState('playing')} onPause={() => setAudioState('paused')} - onEnded={() => setAudioState('not-started')} + onEnded={() => hidePlayer()} onClose={() => hidePlayer()} /> - )} +
); }; diff --git a/packages/ts-components/src/components/article-audio/__tests__/ArticleAudio.test.tsx b/packages/ts-components/src/components/article-audio/__tests__/ArticleAudio.test.tsx index 65f270922b..09d663ed59 100644 --- a/packages/ts-components/src/components/article-audio/__tests__/ArticleAudio.test.tsx +++ b/packages/ts-components/src/components/article-audio/__tests__/ArticleAudio.test.tsx @@ -8,16 +8,21 @@ jest.mock('../styles', () => ({ + ), + AudioDuration: ({ children, style }: any) => ( + + {children} + ) })); jest.mock('@times-components/icons', () => ({ __esModule: true, - PlayIcon: ({ color }: any) => ( - + PlayIcon: ({ fill }: any) => ( + ), - PauseIcon: ({ color }: any) => ( - + PauseIcon: ({ fill }: any) => ( + ) })); @@ -60,53 +65,50 @@ describe('ArticleAudio', () => { const audioButton = getByTestId('audio-button'); expect(audioButton).toBeInTheDocument(); - expect(audioButton.style.backgroundColor).toBe(''); expect(audioButton).toHaveStyle('color: #333'); + expect(audioButton).toHaveStyle('background-color: #fff'); // The initial state should display 'Listen' and the duration expect(getByText('Listen')).toBeInTheDocument(); expect(getByText('3 min')).toBeInTheDocument(); - // Since audioState is 'not-started', duration color should be '#696969' - const durationSpan = getByText('3 min'); + // Verify duration color when 'not-started' + const durationSpan = getByTestId('audio-duration'); expect(durationSpan).toHaveStyle('color: #696969'); }); - test('hides AudioPlayer when close button is clicked (using mocked AudioPlayer)', () => { - const { getByTestId, queryByTestId, container, getByText } = render( + test('handles AudioPlayer visibility toggling', () => { + const { getByTestId, queryByTestId, container } = render( ); - // Trigger the 'loadedmetadata' event to set the duration const audio = container.querySelector('audio') as HTMLAudioElement; act(() => { fireEvent.loadedMetadata(audio); }); - // Initially, the AudioPlayer should not be visible - expect(queryByTestId('audio-player')).not.toBeInTheDocument(); + const audioPlayer = queryByTestId('audioPlayerWrapper'); + + // Verify the player is hidden initially + expect(audioPlayer).toBeInTheDocument(); + // expect(audioPlayer).toHaveStyle('opacity: 0'); + expect(audioPlayer).toHaveStyle('display: none'); - // Click the audio button to start playback + // Click to show the player const audioButton = getByTestId('audio-button'); fireEvent.click(audioButton); - // The mocked AudioPlayer should now be visible - expect(getByTestId('audio-player')).toBeInTheDocument(); - - // Use the mocked Close button inside the AudioPlayer to close it - const closeButton = getByText('Close'); - fireEvent.click(closeButton); - - // The AudioPlayer should no longer be visible - expect(queryByTestId('audio-player')).not.toBeInTheDocument(); + // Verify the player is now visible + // expect(audioPlayer).toHaveStyle('opacity: 1'); + expect(audioPlayer).toHaveStyle('visibility: visible'); }); - test('handles play and pause', () => { + test('handles play and pause state transitions correctly', () => { const { getByTestId, getByText, container } = render( ); - // Trigger the 'loadedmetadata' event to set the duration + // Trigger the 'loadedmetadata' event const audio = container.querySelector('audio') as HTMLAudioElement; act(() => { fireEvent.loadedMetadata(audio); @@ -114,79 +116,75 @@ describe('ArticleAudio', () => { const audioButton = getByTestId('audio-button'); - // Simulate clicking the play button + // Click to play fireEvent.click(audioButton); - - // Now, audioState should be 'playing' + expect(getByText('Playing')).toBeInTheDocument(); expect(audioButton).toHaveStyle('background-color: #1D1D1B'); expect(audioButton).toHaveStyle('color: #fff'); - expect(getByText('Playing')).toBeInTheDocument(); - // Since audioState is 'playing', duration color should be '#fff' - const durationSpan = getByText('3 min'); + // Duration color should change to white + const durationSpan = getByTestId('audio-duration'); expect(durationSpan).toHaveStyle('color: #fff'); - // Simulate clicking the pause button + // Click to pause fireEvent.click(audioButton); - expect(getByText('Paused')).toBeInTheDocument(); - expect(audioButton).toHaveStyle('background-color: #1D1D1B'); - expect(audioButton).toHaveStyle('color: #fff'); - // Simulate clicking the play button again + // Click to play again fireEvent.click(audioButton); - expect(getByText('Playing')).toBeInTheDocument(); }); - test('shows AudioPlayer when audio is played', () => { - const { getByTestId, queryByTestId, container } = render( - - ); - - // Trigger the 'loadedmetadata' event to set the duration - const audio = container.querySelector('audio') as HTMLAudioElement; - act(() => { - fireEvent.loadedMetadata(audio); - }); - - expect(queryByTestId('audio-player')).not.toBeInTheDocument(); - - const audioButton = getByTestId('audio-button'); - fireEvent.click(audioButton); - - expect(getByTestId('audio-player')).toBeInTheDocument(); - }); - - test('updates audioState based on AudioPlayer callbacks', () => { + test('updates audioState via AudioPlayer callbacks', () => { const { getByTestId, getByText, container } = render( ); - // Trigger the 'loadedmetadata' event to set the duration + // Trigger the 'loadedmetadata' event const audio = container.querySelector('audio') as HTMLAudioElement; act(() => { fireEvent.loadedMetadata(audio); }); const audioButton = getByTestId('audio-button'); - fireEvent.click(audioButton); // Start playing - - expect(getByText('Playing')).toBeInTheDocument(); + fireEvent.click(audioButton); // Play const pauseButton = getByText('Pause'); - fireEvent.click(pauseButton); - + fireEvent.click(pauseButton); // Pause expect(getByText('Paused')).toBeInTheDocument(); const playButton = getByText('Play'); - fireEvent.click(playButton); - + fireEvent.click(playButton); // Play again expect(getByText('Playing')).toBeInTheDocument(); const endedButton = getByText('Ended'); - fireEvent.click(endedButton); - + fireEvent.click(endedButton); // Simulate end of playback expect(getByText('Listen')).toBeInTheDocument(); }); }); +test('hides AudioPlayer when close button is clicked', () => { + const { getByTestId, getByText, container } = render( + + ); + + // Trigger 'loadedmetadata' event to initialize duration + const audio = container.querySelector('audio') as HTMLAudioElement; + act(() => { + fireEvent.loadedMetadata(audio); + }); + + // Click the audio button to show the AudioPlayer + const audioButton = getByTestId('audio-button'); + fireEvent.click(audioButton); + + // Verify that the AudioPlayer is now visible + const audioPlayer = getByTestId('audioPlayerWrapper'); + expect(audioPlayer).toHaveStyle('display: block'); + + // Simulate clicking the close button inside the AudioPlayer + const closeButton = getByText('Close'); + fireEvent.click(closeButton); + + // Verify that the AudioPlayer is hidden again + expect(audioPlayer).toHaveStyle('display: none'); +}); diff --git a/packages/ts-components/src/components/article-audio/__tests__/Styles.test.tsx b/packages/ts-components/src/components/article-audio/__tests__/Styles.test.tsx index bff141f633..514fc50e60 100644 --- a/packages/ts-components/src/components/article-audio/__tests__/Styles.test.tsx +++ b/packages/ts-components/src/components/article-audio/__tests__/Styles.test.tsx @@ -14,7 +14,7 @@ describe('AudioButton', () => { expect(button).toHaveStyleRule('background-color', 'unset'); expect(button).toHaveStyleRule('border-radius', '0'); - expect(button).toHaveStyleRule('padding', '7px 11px'); + expect(button).toHaveStyleRule('padding', '6px 11px'); expect(button).toHaveStyleRule('border', '1px solid #333333'); expect(button).toHaveStyleRule('display', 'flex'); expect(button).toHaveStyleRule('align-items', 'center'); diff --git a/packages/ts-components/src/components/article-audio/styles.ts b/packages/ts-components/src/components/article-audio/styles.ts index 9057d41ef1..76e59df974 100644 --- a/packages/ts-components/src/components/article-audio/styles.ts +++ b/packages/ts-components/src/components/article-audio/styles.ts @@ -1,10 +1,17 @@ import styled from 'styled-components'; -import { colours } from '@times-components/ts-styleguide'; +import { colours, breakpoints } from '@times-components/ts-styleguide'; +export const AudioDuration = styled.span` + display: none; + + @media (min-width: ${breakpoints.small}px) { + display: block; + } +`; export const AudioButton = styled.button` background-color: unset; border-radius: 0; - padding: 7px 11px; + padding: 6px 11px; border: 1px solid ${colours.functional.primary}; display: flex; align-items: center;