diff --git a/scripts/generate-icons/used-icons-list.json b/scripts/generate-icons/used-icons-list.json index 0ee7b0d67b..a880045233 100644 --- a/scripts/generate-icons/used-icons-list.json +++ b/scripts/generate-icons/used-icons-list.json @@ -21,6 +21,7 @@ "Email", "Error", "ErrorOutline", + "GraphicEq", "HighlightOff", "Image", "Info", diff --git a/src/audio-player-composable/__tests__/audio-player-composable.stories.tsx b/src/audio-player-composable/__tests__/audio-player-composable.stories.tsx index 55379f5eab..c20e9271ea 100644 --- a/src/audio-player-composable/__tests__/audio-player-composable.stories.tsx +++ b/src/audio-player-composable/__tests__/audio-player-composable.stories.tsx @@ -25,7 +25,13 @@ import { IconFilledLaunch, IconFilledReplay5, IconFilledForward5, + IconFilledGraphicEq, } from '../../icons'; +import {Flag} from '../../flag'; + +const AUDIO_SRC = + 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3'; +const LIVE_AUDIO_SRC = 'https://radio.talkradio.co.uk/stream'; const myCustomTheme = createTheme({ name: 'my-custom-audio-player-theme', @@ -68,25 +74,31 @@ export default { const fullAudioPlayerAreasDesktop = ` seekBar seekBar seekBar seekBar seekBar seekBar seekBar - currentTime none none none none none totalTime + currentTime none none none none none totalTime volume prev backward play forward next link `; const fullAudioPlayerAreasMobile = ` seekBar seekBar seekBar seekBar seekBar - currentTime volume none link totalTime + currentTime volume none link totalTime prev backward play forward next `; -const AudioPlayerFull = (props: { +const fullAudioPlayerLiveAreasDesktop = ` + live prev backward play forward next link + `; + +const fullAudioPlayerLiveAreasMobile = ` + none none none link live + prev backward play forward next +`; + +const AudioPlayerFullRecorded = (props: { ariaLandmark: string; src?: string; autoPlay?: boolean; }) => ( - + ); +const AudioPlayerFullLive = (props: { + ariaLandmark: string; + src?: string; + autoPlay?: boolean; +}) => ( + + + {Areas => ( + <> + + + -const AudioPlayerInline = (props: {ariaLandmark: string; src?: string}) => ( - + + + + + + + + + + console.log('on skip Prev track')} + /> + + + + console.log('on skip Next track')} + /> + + + + + + Live + + + + + + { + window.open( + 'https://www.newskit.co.uk/', + '', + 'width=380,height=665', + ); + }} + > + + + + + + )} + + +); + +const AudioPlayerInlineRecorded = (props: { + ariaLandmark: string; + src?: string; +}) => ( + ( ); +const AudioPlayerInlineLive = (props: {ariaLandmark: string; src?: string}) => ( + + + + + + Live + + + +); + export const AudioPlayer = () => ( <> - Full player-recorded - + Audio Player - full recorded + +
+ Audio Player - full live + +

+ Audio Player - inline recorded +
- Audio player inline recorded - + Audio Player - inline live + ); AudioPlayer.storyName = 'audio-player'; @@ -211,7 +320,7 @@ export const AudioSubComponents = () => (
( format={({duration}) => calculateTime(duration)} /> + + live + + + Live + + default @@ -276,7 +392,7 @@ export const AudioPlayerOverrides = () => ( Audio player with overrides ( <> Autoplay - + ); @@ -425,7 +541,7 @@ AudioPlayPauseButtonAutoplay.storyName = 'audio-play-pause-button-autoplay'; export const AudioPlayerKeyboard = () => ( <> Audio Player Keyboard shortcuts - +
k / space
@@ -449,7 +565,7 @@ export const AudioPlayerKeyboard = () => ( Audio Player Keyboard overrides shortcuts , +}; + const recordedAudioProps: AudioPlayerComposableProps = { src: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3', autoPlay: false, @@ -87,6 +94,15 @@ const recordedTrackingOutputObject = { }, }; +const liveTrackingOutputObject = { + originator: 'audio-player-play-button', + trigger: 'click', + context: { + media_player: `newskit-audio-player-${version}`, + media_type: 'audio', + }, +}; + const recordedSeekBarOverrides: AudioPlayerComposableProps = { src: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3', autoPlay: false, @@ -241,6 +257,36 @@ describe('Audio Player Composable', () => { expect(audioElement.paused).toBe(true); }); + it('should have play or stop label when live', () => { + const {getByTestId} = renderWithTheme( + AudioPlayerComposable, + liveAudioProps, + ); + + const playPauseButton = getByTestId('audio-player-play-pause-button'); + + fireEvent.canPlay(getByTestId('audio-element')); + fireEvent.click(playPauseButton); + expect(playPauseButton.getAttribute('aria-label')).toBe('Stop'); + fireEvent.click(playPauseButton); + expect(playPauseButton.getAttribute('aria-label')).toBe('Play'); + }); + + it('should have play or pause label when recorded', () => { + const {getByTestId} = renderWithTheme( + AudioPlayerComposable, + recordedAudioProps, + ); + + const playPauseButton = getByTestId('audio-player-play-pause-button'); + + fireEvent.canPlay(getByTestId('audio-element')); + fireEvent.click(playPauseButton); + expect(playPauseButton.getAttribute('aria-label')).toBe('Pause'); + fireEvent.click(playPauseButton); + expect(playPauseButton.getAttribute('aria-label')).toBe('Play'); + }); + it('should skip 10 seconds with forward or replay button button click', () => { const {getByTestId} = renderWithTheme( AudioPlayerComposable, @@ -314,26 +360,6 @@ describe('Audio Player Composable', () => { expect(playPauseButton).toMatchSnapshot(); }); - it('should fire "end" event when the track has ended', () => { - const fireEventSpy = jest.fn(); - const {getByTestId} = renderWithImplementation( - AudioPlayerComposable, - recordedAudioProps, - fireEventSpy, - ); - - const expectedObject = { - ...recordedTrackingOutputObject, - originator: 'audio-complete', - trigger: 'end', - }; - - const player = getByTestId('audio-element'); - fireEvent.ended(player); - - expect(fireEventSpy).toHaveBeenCalledWith(expectedObject); - }); - it('should preserve playing state when changing track', () => { const {getByTestId, rerender} = renderWithTheme( AudioPlayerComposable, @@ -732,4 +758,259 @@ describe('Audio Player Composable', () => { expect(mockOnNextClick).toHaveBeenCalled(); }); }); + + describe('Instrumentation tests', () => { + test('should raise "end" event when the track has ended', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioProps, + fireEventSpy, + ); + + const expectedObject = { + ...recordedTrackingOutputObject, + originator: 'audio-complete', + trigger: 'end', + }; + + const player = getByTestId('audio-element'); + fireEvent.ended(player); + + expect(fireEventSpy).toHaveBeenCalledWith(expectedObject); + }); + + test('should raise "click" event when recorded is paused', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioProps, + fireEventSpy, + ); + const expectedObject = { + ...recordedTrackingOutputObject, + originator: 'audio-player-pause-button', + trigger: 'click', + }; + + const playPause = getByTestId('audio-player-play-pause-button'); + fireEvent.canPlay(getByTestId('audio-element')); + fireEvent.click(playPause); + fireEvent.click(playPause); + + expect(fireEventSpy).toHaveBeenLastCalledWith(expectedObject); + }); + + test('should raise "click" event when recorded is played', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioProps, + fireEventSpy, + ); + + const expectedObject = { + ...recordedTrackingOutputObject, + originator: 'audio-player-play-button', + trigger: 'click', + }; + + const playButton = getByTestId('audio-player-play-pause-button'); + fireEvent.canPlay(getByTestId('audio-element')); + fireEvent.click(playButton); + + expect(fireEventSpy).toHaveBeenLastCalledWith(expectedObject); + }); + + test('should raise "click" event when live is stopped', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + liveAudioProps, + fireEventSpy, + ); + const expectedObject = { + ...liveTrackingOutputObject, + originator: 'audio-player-stop-button', + trigger: 'click', + }; + + const playStop = getByTestId('audio-player-play-pause-button'); + fireEvent.canPlay(getByTestId('audio-element')); + fireEvent.click(playStop); + fireEvent.click(playStop); + + expect(fireEventSpy).toHaveBeenLastCalledWith(expectedObject); + }); + + test('should raise "click" event when live is played', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + liveAudioProps, + fireEventSpy, + ); + + const playButton = getByTestId('audio-player-play-pause-button'); + fireEvent.canPlay(getByTestId('audio-element')); + fireEvent.click(playButton); + + expect(fireEventSpy).toHaveBeenLastCalledWith(liveTrackingOutputObject); + }); + + test('should raise "click" event when skip forward button is clicked', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioProps, + fireEventSpy, + ); + + const forwardButton = getByTestId('audio-player-forward-button'); + fireEvent.click(forwardButton); + + expect(fireEventSpy).toHaveBeenCalledWith({ + ...recordedTrackingOutputObject, + context: { + event_navigation_name: 'forward skip', + ...recordedTrackingOutputObject.context, + }, + originator: 'audio-player-skip-forward', + trigger: 'click', + }); + }); + + test('should raise "click" event when backward button is clicked', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioProps, + fireEventSpy, + ); + + const backwardButton = getByTestId('audio-player-replay-button'); + fireEvent.click(backwardButton); + + expect(fireEventSpy).toHaveBeenCalledWith({ + ...recordedTrackingOutputObject, + context: { + event_navigation_name: 'backward skip', + ...recordedTrackingOutputObject.context, + }, + originator: 'audio-player-skip-backward', + trigger: 'click', + }); + }); + + test('should raise event when the track has ended', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioProps, + fireEventSpy, + ); + + const expectedObject = { + ...recordedTrackingOutputObject, + originator: 'audio-complete', + trigger: 'end', + }; + + const player = getByTestId('audio-element'); + fireEvent.ended(player); + + expect(fireEventSpy).toHaveBeenCalledWith(expectedObject); + }); + + test('raise event when audio player autoplays', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioPropsAutoplay, + fireEventSpy, + ); + + const expectedObject = { + ...recordedTrackingOutputObject, + originator: 'audio-player-audio', + trigger: 'start', + }; + + const play = getByTestId('audio-player-play-pause-button'); + fireEvent.canPlay(getByTestId('audio-element')); + fireEvent.click(play); + fireEvent.click(play); + + expect(fireEventSpy).toHaveBeenCalledWith(expectedObject); + }); + + test('should raise event while the audio is being played', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioProps, + fireEventSpy, + ); + + const audioElement = getByTestId('audio-element') as HTMLAudioElement; + fireEvent.durationChange(audioElement, { + target: { + duration: 60, + }, + }); + audioElement.currentTime = 1; + fireEvent.timeUpdate(audioElement); + + const expectedObject = { + ...recordedTrackingOutputObject, + originator: 'audio-player-audio', + trigger: 'pulse', + context: { + media_duration: '01:00', + media_milestone: '0', + media_offset: '00:00', + media_player: 'newskit-audio-player-0.10.0', + media_segment: 'MockMediaSegment', + media_type: 'audio', + }, + }; + expect(fireEventSpy).toHaveBeenCalledWith(expectedObject); + }); + + test('should not raise play event if play called twice', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioProps, + fireEventSpy, + ); + const audioElement = getByTestId('audio-element') as HTMLAudioElement; + + // Two play calls, should cause one event + fireEvent.canPlay(getByTestId('audio-element')); + fireEvent.play(audioElement); + fireEvent.play(audioElement); + + expect(fireEventSpy).toHaveBeenCalledTimes(1); + }); + + test('should not raise pause event if play called twice', () => { + const fireEventSpy = jest.fn(); + const {getByTestId} = renderWithImplementation( + AudioPlayerComposable, + recordedAudioProps, + fireEventSpy, + ); + const audioElement = getByTestId('audio-element') as HTMLAudioElement; + + fireEvent.play(audioElement); + fireEventSpy.mockReset(); + + // Two pause calls, should cause one event + fireEvent.pause(audioElement); + fireEvent.pause(audioElement); + + expect(fireEventSpy).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/src/audio-player-composable/audio-functions.ts b/src/audio-player-composable/audio-functions.ts index b0ad151804..a2043b7777 100644 --- a/src/audio-player-composable/audio-functions.ts +++ b/src/audio-player-composable/audio-functions.ts @@ -45,9 +45,7 @@ export const useAudioFunctions = ({ media_type: 'audio', }; return live - ? // TODO remove ignore once in implemented live - /* istanbul ignore next */ - playerData + ? playerData : { ...playerData, media_duration: formatTrackTime(duration), @@ -196,8 +194,6 @@ export const useAudioFunctions = ({ fireEvent( getTrackingInformation( - // TODO remove ignore once implemented live functionality - /* istanbul ignore next */ live ? 'audio-player-stop-button' : 'audio-player-pause-button', EventTrigger.Click, ), diff --git a/src/audio-player-composable/audio-player-composable.tsx b/src/audio-player-composable/audio-player-composable.tsx index 3ed1bd99f8..dd96662160 100644 --- a/src/audio-player-composable/audio-player-composable.tsx +++ b/src/audio-player-composable/audio-player-composable.tsx @@ -41,9 +41,7 @@ const defaultKeyboardShortcuts = { export const AudioPlayerComposable = ({ children, src, - /* istanbul ignore next */ autoPlay = false, - /* istanbul ignore next */ live = false, ariaLandmark, keyboardShortcuts: keyboardShortcutsProp, @@ -73,7 +71,6 @@ export const AudioPlayerComposable = ({ setDisplayDuration(0); }, [src]); - // @ts-ignore as we are not passing all the parameters yet. const { audioEvents, togglePlay, @@ -95,6 +92,7 @@ export const AudioPlayerComposable = ({ duration, setDuration, src, + live, } as AudioFunctionDependencies); const getPlayPauseButtonProps = useCallback( @@ -113,8 +111,6 @@ export const AudioPlayerComposable = ({ if (playing) { ariaPressed = true; - // TODO remove ignore as we implement the "live" functionality back and write test for it - /* istanbul ignore next */ if (canPause) { playStateIcon = ; ariaLabel = 'Pause';