[tests] Add test coverage
All checks were successful
Deploy to mopidy1 / deploy (push) Successful in 34s
All checks were successful
Deploy to mopidy1 / deploy (push) Successful in 34s
This commit is contained in:
131
__tests__/components/PlaybackControls.test.js
Normal file
131
__tests__/components/PlaybackControls.test.js
Normal file
@ -0,0 +1,131 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-test-renderer';
|
||||
import { render } from '../test-wrapper';
|
||||
import PlaybackControls from '../../src/js/components/PlaybackControls';
|
||||
import state from '../state';
|
||||
|
||||
const mockState = {
|
||||
...state,
|
||||
mopidy: {
|
||||
...state.mopidy,
|
||||
time_position: 0,
|
||||
volume: 50,
|
||||
mute: false,
|
||||
play_state: 'stopped',
|
||||
consume: false,
|
||||
random: false,
|
||||
repeat: false,
|
||||
host: 'localhost',
|
||||
port: '6680',
|
||||
ssl: false,
|
||||
},
|
||||
ui: {
|
||||
...state.ui,
|
||||
touch_enabled: false,
|
||||
sidebar_open: false,
|
||||
slim_mode: false,
|
||||
},
|
||||
core: {
|
||||
...state.core,
|
||||
streamTitle: null,
|
||||
current_track: null,
|
||||
next_track_uri: null,
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('react-redux', () => ({
|
||||
useSelector: jest.fn().mockImplementation((func) => func(mockState)),
|
||||
useDispatch: () => jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../src/js/components/Icon', () => 'Icon');
|
||||
jest.mock('../../src/js/components/Link', () => 'Link');
|
||||
jest.mock('../../src/js/components/Thumbnail', () => 'Thumbnail');
|
||||
jest.mock('../../src/js/components/LinksSentence', () => 'LinksSentence');
|
||||
jest.mock('../../src/js/components/Fields/ProgressSlider', () => 'ProgressSlider');
|
||||
jest.mock('../../src/js/components/Fields/VolumeControl', () => 'VolumeControl');
|
||||
jest.mock('../../src/js/components/Fields/MuteControl', () => 'MuteControl');
|
||||
jest.mock('../../src/js/components/Fields/OutputControl', () => 'OutputControl');
|
||||
|
||||
function findSmartQueueButton(renderer) {
|
||||
const buttons = renderer.root.findAllByType('button');
|
||||
return buttons.find((btn) => {
|
||||
if (!btn.props.children) return false;
|
||||
const children = Array.isArray(btn.props.children)
|
||||
? btn.props.children
|
||||
: [btn.props.children];
|
||||
return children.some(
|
||||
(child) => child.props && child.props.name === 'auto_awesome',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
describe('<PlaybackControls />', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
jest.clearAllMocks();
|
||||
global.fetch = jest.fn(() => Promise.resolve({ ok: true }));
|
||||
});
|
||||
|
||||
it('should render correctly', () => {
|
||||
const result = render(<PlaybackControls />).toJSON();
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render smart queue button in settings section', () => {
|
||||
const renderer = render(<PlaybackControls />);
|
||||
expect(findSmartQueueButton(renderer)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have inactive smart queue button by default', () => {
|
||||
const renderer = render(<PlaybackControls />);
|
||||
const btn = findSmartQueueButton(renderer);
|
||||
expect(btn.props.className).not.toContain('control--active');
|
||||
});
|
||||
|
||||
it('should toggle active class on click and call fetch', () => {
|
||||
const renderer = render(<PlaybackControls />);
|
||||
const btn = findSmartQueueButton(renderer);
|
||||
act(() => { btn.props.onClick(); });
|
||||
|
||||
const newBtn = findSmartQueueButton(renderer);
|
||||
expect(newBtn.props.className).toContain('control--active');
|
||||
expect(global.fetch).toHaveBeenCalledTimes(1);
|
||||
expect(global.fetch).toHaveBeenCalledWith(
|
||||
'http://localhost:6680/smartplaylists/smart-queue',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ enabled: true }),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should send enabled=false on second click', () => {
|
||||
const renderer = render(<PlaybackControls />);
|
||||
let btn = findSmartQueueButton(renderer);
|
||||
act(() => { btn.props.onClick(); });
|
||||
|
||||
btn = findSmartQueueButton(renderer);
|
||||
act(() => { btn.props.onClick(); });
|
||||
|
||||
expect(global.fetch).toHaveBeenCalledTimes(2);
|
||||
expect(global.fetch).toHaveBeenLastCalledWith(
|
||||
'http://localhost:6680/smartplaylists/smart-queue',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ enabled: false }),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should restore smart queue state from localStorage', () => {
|
||||
localStorage.setItem('smartQueue', 'true');
|
||||
const renderer = render(<PlaybackControls />);
|
||||
const btn = findSmartQueueButton(renderer);
|
||||
expect(btn.props.className).toContain('control--active');
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
284
__tests__/components/__snapshots__/PlaybackControls.test.js.snap
Normal file
284
__tests__/components/__snapshots__/PlaybackControls.test.js.snap
Normal file
@ -0,0 +1,284 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<PlaybackControls /> should render correctly 1`] = `
|
||||
<div
|
||||
className="playback-controls"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="div"
|
||||
>
|
||||
<div
|
||||
className="playback-controls__background"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="div"
|
||||
/>
|
||||
<div
|
||||
className="current-track__wrapper"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="div"
|
||||
>
|
||||
<div
|
||||
className="current-track"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="div"
|
||||
tabIndex="-1"
|
||||
>
|
||||
<Link
|
||||
className="thumbnail-wrapper"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Link"
|
||||
tabIndex="-1"
|
||||
to="/modal/kiosk-mode"
|
||||
>
|
||||
<Thumbnail
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Thumbnail"
|
||||
size="small"
|
||||
type="track"
|
||||
/>
|
||||
</Link>
|
||||
<div
|
||||
className="text"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="div"
|
||||
>
|
||||
<div
|
||||
className="title"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="div"
|
||||
>
|
||||
|
||||
</div>
|
||||
<div
|
||||
className="artist"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="div"
|
||||
>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section
|
||||
className="playback"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="section"
|
||||
>
|
||||
<button
|
||||
className="control previous"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Icon
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Icon"
|
||||
name="navigate_before"
|
||||
type="material"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
className="control play"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Icon
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Icon"
|
||||
name="play_circle_filled"
|
||||
type="material"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
className="control next"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Icon
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Icon"
|
||||
name="navigate_next"
|
||||
type="material"
|
||||
/>
|
||||
</button>
|
||||
</section>
|
||||
<section
|
||||
className="progress"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="section"
|
||||
>
|
||||
<div
|
||||
className="time time--current"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="div"
|
||||
>
|
||||
-
|
||||
</div>
|
||||
<ProgressSlider
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="ProgressSlider"
|
||||
playbackPosition={0}
|
||||
/>
|
||||
<div
|
||||
className="time time--total"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="div"
|
||||
>
|
||||
-
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
className="settings"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="section"
|
||||
>
|
||||
<button
|
||||
className="control tooltip"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Icon
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Icon"
|
||||
name="restaurant"
|
||||
type="material"
|
||||
/>
|
||||
<span
|
||||
className="tooltip__content"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="span"
|
||||
>
|
||||
Consume
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="control tooltip"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Icon
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Icon"
|
||||
name="auto_awesome"
|
||||
type="material"
|
||||
/>
|
||||
<span
|
||||
className="tooltip__content"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="span"
|
||||
>
|
||||
Smart Queue
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="control tooltip"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Icon
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Icon"
|
||||
name="shuffle"
|
||||
type="material"
|
||||
/>
|
||||
<span
|
||||
className="tooltip__content"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="span"
|
||||
>
|
||||
Shuffle
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="control tooltip"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Icon
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Icon"
|
||||
name="repeat"
|
||||
type="material"
|
||||
/>
|
||||
<span
|
||||
className="tooltip__content"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="span"
|
||||
>
|
||||
Repeat
|
||||
</span>
|
||||
</button>
|
||||
<OutputControl
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="OutputControl"
|
||||
/>
|
||||
</section>
|
||||
<section
|
||||
className="volume"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="section"
|
||||
>
|
||||
<MuteControl
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="MuteControl"
|
||||
mute={false}
|
||||
onMuteChange={[Function]}
|
||||
/>
|
||||
<VolumeControl
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="VolumeControl"
|
||||
mute={false}
|
||||
onVolumeChange={[Function]}
|
||||
scrollWheel={true}
|
||||
volume={50}
|
||||
/>
|
||||
</section>
|
||||
<section
|
||||
className="triggers"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="section"
|
||||
>
|
||||
<button
|
||||
className="control expanded-controls"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Icon
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Icon"
|
||||
name="expand_less"
|
||||
type="material"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
className="control sidebar-toggle"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="button"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Icon
|
||||
className="open"
|
||||
data-qa-file="PlaybackControls"
|
||||
data-qa-node="Icon"
|
||||
name="menu"
|
||||
type="material"
|
||||
/>
|
||||
</button>
|
||||
</section>
|
||||
</div>
|
||||
`;
|
||||
Reference in New Issue
Block a user