UNPKG

@wordpress/block-library

Version:
273 lines (241 loc) 6.65 kB
import { beforeEach, describe, expect, it, vi } from 'vitest'; import { fireEvent, render, screen } from '@testing-library/react'; import { useDispatch, useSelect } from '@wordpress/data'; import PlaylistEdit from '../edit'; let mediaPlaceholderProps; let mediaReplaceFlowProps; // The tracks the playlist holds. The inner blocks mock renders these, so a // test can look at what ended up in the tracklist. let mockTracks = []; vi.mock( '@wordpress/block-editor', () => ( { store: {}, BlockControls: ( { children } ) => <div>{ children }</div>, BlockIcon: () => <span />, InspectorControls: ( { children } ) => <div>{ children }</div>, MediaPlaceholder: ( props ) => { mediaPlaceholderProps = props; return <div />; }, MediaReplaceFlow: ( props ) => { mediaReplaceFlowProps = props; return ( <button onClick={ () => props.onSelect( { id: 2, url: 'https://example.com/second-track.mp3', title: 'Second track', } ) } > { props.name } </button> ); }, useBlockProps: () => ( { className: 'wp-block-playlist' } ), useInnerBlocksProps: ( blockProps ) => ( { ...blockProps, children: mockTracks.map( ( track ) => ( <li key={ track.clientId } data-testid="playlist-track"> { track.attributes.title } </li> ) ), } ), __experimentalColorGradientSettingsDropdown: () => <div />, __experimentalUseMultipleOriginColorsAndGradients: () => ( { colors: [], gradients: [], disableCustomColors: true, disableCustomGradients: true, } ), } ) ); vi.mock( '@wordpress/blocks', () => ( { createBlock: vi.fn( ( name, attributes ) => ( { name, attributes, clientId: 'new-track', } ) ), } ) ); vi.mock( '@wordpress/blob', () => ( { createBlobURL: vi.fn( () => 'blob:track' ), } ) ); vi.mock( '@wordpress/components', () => ( { Disabled: ( { children } ) => <div>{ children }</div>, SelectControl: () => <div />, ToggleControl: () => <div />, __experimentalToolsPanel: ( { children } ) => <div>{ children }</div>, __experimentalToolsPanelItem: ( { children } ) => <div>{ children }</div>, } ) ); vi.mock( '@wordpress/data', () => ( { useDispatch: vi.fn(), useSelect: vi.fn(), } ) ); vi.mock( '@wordpress/i18n', () => ( { __: ( text ) => text, _x: ( text ) => text, } ) ); vi.mock( '@wordpress/icons', () => ( { playlist: 'playlist', } ) ); vi.mock( '@wordpress/notices', () => ( { store: {}, } ) ); vi.mock( '../../utils/caption', () => ( { Caption: () => <figcaption />, } ) ); vi.mock( '../../utils/hooks', () => ( { useToolsPanelDropdownMenuProps: () => ( {} ), } ) ); vi.mock( '../../utils/waveform-player', () => ( { WaveformPlayer: () => <div />, } ) ); const defaultAttributes = { order: 'asc', showTracklist: true, showNumbers: true, showImages: true, showPlayButtonArtwork: false, showArtists: true, showTrackLength: true, }; describe( 'PlaylistEdit', () => { let replaceInnerBlocks; let insertBlocks; let selectBlock; // The playlist reads its tracks from the store and changes them through // dispatched actions. Keeping a list here lets a test assert which tracks // the playlist ends up with, rather than which action it reached for. const trackStore = ( initial ) => { mockTracks = initial; useSelect.mockImplementation( () => ( { innerBlockTracks: mockTracks, } ) ); insertBlocks.mockImplementation( ( blocks, index ) => { const at = index ?? mockTracks.length; mockTracks = [ ...mockTracks.slice( 0, at ), ...blocks, ...mockTracks.slice( at ), ]; } ); replaceInnerBlocks.mockImplementation( ( _clientId, next ) => { mockTracks = next; } ); }; const trackClientIds = () => mockTracks.map( ( track ) => track.clientId ); beforeEach( () => { mediaPlaceholderProps = undefined; mediaReplaceFlowProps = undefined; replaceInnerBlocks = vi.fn(); insertBlocks = vi.fn(); selectBlock = vi.fn(); useDispatch.mockReturnValue( { createErrorNotice: vi.fn(), replaceInnerBlocks, insertBlocks, selectBlock, __unstableMarkNextChangeAsNotPersistent: vi.fn(), } ); trackStore( [ { clientId: 'track-1', attributes: { id: 1, src: 'https://example.com/audio.mp3', title: 'Sample track', }, }, ] ); } ); it( 'lets users select audio tracks individually from the Media Library', () => { trackStore( [] ); render( <PlaylistEdit attributes={ defaultAttributes } clientId="playlist-1" insertBlocksAfter={ vi.fn() } isSelected={ false } setAttributes={ vi.fn() } /> ); expect( mediaPlaceholderProps.multiple ).toBe( 'add' ); } ); it( 'lets users select additional audio tracks individually from the Media Library', () => { render( <PlaylistEdit attributes={ defaultAttributes } clientId="playlist-1" insertBlocksAfter={ vi.fn() } isSelected={ false } setAttributes={ vi.fn() } /> ); expect( mediaReplaceFlowProps.multiple ).toBe( 'add' ); } ); it( 'keeps track blocks mounted when the tracklist is hidden', () => { render( <PlaylistEdit attributes={ { ...defaultAttributes, showTracklist: false, } } clientId="playlist-1" insertBlocksAfter={ vi.fn() } isSelected={ false } setAttributes={ vi.fn() } /> ); const tracklist = screen.getByRole( 'list' ); expect( tracklist ).toHaveClass( 'wp-block-playlist__tracklist-is-hidden' ); expect( screen.getByTestId( 'playlist-track' ) ).toBeInTheDocument(); } ); it( 'preserves placeholder tracks when adding tracks', () => { trackStore( [ { clientId: 'track-1', attributes: { id: 1, src: 'https://example.com/audio.mp3', title: 'Sample track', }, }, // A track the user added but has not filled in yet. { clientId: 'placeholder-track', attributes: {} }, ] ); render( <PlaylistEdit attributes={ defaultAttributes } clientId="playlist-1" insertBlocksAfter={ vi.fn() } isSelected={ false } setAttributes={ vi.fn() } /> ); fireEvent.click( screen.getByRole( 'button', { name: 'Add track' } ) ); expect( trackClientIds() ).toEqual( [ 'track-1', 'placeholder-track', 'new-track', ] ); } ); it( 'adds tracks from the add track control', () => { render( <PlaylistEdit attributes={ defaultAttributes } clientId="playlist-1" insertBlocksAfter={ vi.fn() } isSelected={ false } setAttributes={ vi.fn() } /> ); fireEvent.click( screen.getByRole( 'button', { name: 'Add track', } ) ); expect( trackClientIds() ).toEqual( [ 'track-1', 'new-track' ] ); expect( selectBlock ).toHaveBeenCalledWith( 'new-track' ); } ); } );