fix(player): toggle current track without restarting playback
ci / ts / ts (packages + web) (push) Failing after 7m39s
release / android (APK в релиз) (push) Successful in 6m47s
release / desktop (Linux и Windows в релиз) (push) Successful in 15m18s
release / release (версия и заметки) (push) Successful in 9s
release / prune (старые файлы и прогоны) (push) Successful in 10s
ci / ts / ts (packages + web) (push) Failing after 7m39s
release / android (APK в релиз) (push) Successful in 6m47s
release / desktop (Linux и Windows в релиз) (push) Successful in 15m18s
release / release (версия и заметки) (push) Successful in 9s
release / prune (старые файлы и прогоны) (push) Successful in 10s
This commit is contained in:
1 parent
5876ae29cc
commit
6a1382dad5
3 files changed
+45
-4
No files matched your search
@@ -531,6 +531,41 @@ describe('search box', () => {
|
||||
});
|
||||
|
||||
describe('player', () => {
|
||||
it.each(['album', 'artist'] as const)('toggles the current %s row without restarting or replacing the listening attempt', async (kind) => {
|
||||
const alice = makeUser('alice', 'user');
|
||||
const id = kind === 'artist' ? '00000000-0000-4000-8000-0000000000aa' : '00000000-0000-4000-8000-0000000000bb';
|
||||
const { user, api } = await renderApp([alice], `/${kind}/${id}`, { signedInAs: alice });
|
||||
const row = (await screen.findByText('Закрой за мной дверь')).closest('[role="listitem"]')!;
|
||||
await user.click(row);
|
||||
const bar = screen.getByRole('contentinfo', { name: 'Плеер' });
|
||||
await waitFor(() => expect(within(bar).getByRole('button', { name: 'Пауза' })).toBeInTheDocument());
|
||||
await user.keyboard('{ArrowRight}');
|
||||
const progress = within(bar).getByRole('slider', { name: 'Позиция' });
|
||||
expect(progress).toHaveValue('10000');
|
||||
await user.click(row);
|
||||
expect(within(bar).getByRole('button', { name: 'Слушать' })).toBeInTheDocument();
|
||||
expect(progress).toHaveValue('10000');
|
||||
await user.click(row);
|
||||
expect(within(bar).getByRole('button', { name: 'Пауза' })).toBeInTheDocument();
|
||||
expect(progress).toHaveValue('10000');
|
||||
await user.keyboard('{Enter}');
|
||||
expect(within(bar).getByRole('button', { name: 'Слушать' })).toBeInTheDocument();
|
||||
await user.keyboard('{Enter}');
|
||||
expect(within(bar).getByRole('button', { name: 'Пауза' })).toBeInTheDocument();
|
||||
expect(progress).toHaveValue('10000');
|
||||
window.dispatchEvent(new Event('pagehide'));
|
||||
await waitFor(() => {
|
||||
const events = api.calls.filter((c) => c.path === '/api/v1/events').flatMap((c) => (c.body as { events: { type: string; context_type?: string }[] }).events);
|
||||
expect(events.filter((event) => event.type === 'play_start')).toHaveLength(1);
|
||||
expect(events.find((event) => event.type === 'play_start')).toMatchObject({ context_type: kind });
|
||||
expect(events.some((event) => event.type === 'skip')).toBe(false);
|
||||
});
|
||||
const other = screen.getAllByText('Группа крови').map((node) => node.closest('[role="listitem"]')).find(Boolean)!;
|
||||
await user.click(other);
|
||||
await waitFor(() => expect(within(bar).getByText('Группа крови')).toBeInTheDocument());
|
||||
expect(progress).toHaveValue('0');
|
||||
});
|
||||
|
||||
it('opens a shared track after login and copies its page URL from the player', async () => {
|
||||
const alice = makeUser('alice', 'user');
|
||||
const path = '/track/00000000-0000-4000-8000-000000000101';
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useSession } from '../app/session';
|
||||
import { formatDuration } from '../shared/lib/format';
|
||||
import { usePlayer, usePlayerState } from '../player/context';
|
||||
import type { PlayContext } from '../player/player';
|
||||
import { albumIcon, likeFillIcon, likeIcon, personIcon, playIcon, undoIcon} from '../shared/ui/icons';
|
||||
import { albumIcon, likeFillIcon, likeIcon, pauseIcon, personIcon, playIcon, undoIcon} from '../shared/ui/icons';
|
||||
import { cx, Icon } from '../shared/ui/ui';
|
||||
import s from './catalog.module.css';
|
||||
|
||||
@@ -143,7 +143,7 @@ export function AlbumGrid({ albums }: { albums: AlbumSummary[] }) {
|
||||
|
||||
/**
|
||||
* Список треков. showAlbum — колонка альбома (поиск); numbered — номер трека (страница альбома).
|
||||
* Клик по строке запускает весь список с этого трека в контексте context; Enter — то же с клавиатуры.
|
||||
* Клик или Enter запускает список с выбранного трека; у текущего трека переключает паузу без перезапуска.
|
||||
*/
|
||||
export function TrackList({
|
||||
tracks,
|
||||
@@ -183,7 +183,11 @@ export function TrackList({
|
||||
|
||||
const row = (tr: Track, i: number) => {
|
||||
const isCurrent = current?.id === tr.id;
|
||||
const play = () => tr.available && player.playList(tracks, i, context);
|
||||
const play = () => {
|
||||
if (!tr.available) return;
|
||||
if (isCurrent) player.toggle();
|
||||
else player.playList(tracks, i, context);
|
||||
};
|
||||
const liked = tr.reaction === 'like';
|
||||
const meta = rowMeta?.(tr, i);
|
||||
return (
|
||||
@@ -206,7 +210,7 @@ export function TrackList({
|
||||
{numbered ? (tr.track_no ?? i + 1) : <Cover album={tr.album} size={lead ? 44 : 40} />}
|
||||
{tr.available && (
|
||||
<span className={s.playHint} aria-hidden>
|
||||
<Icon src={playIcon} size={20} />
|
||||
<Icon src={isCurrent && playing ? pauseIcon : playIcon} size={20} />
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
|
||||
@@ -472,6 +472,8 @@ export function fakeApi(initial: FakeUser[]) {
|
||||
return json({ ...kino, album_count: 1, track_count: 0 });
|
||||
case `GET /api/v1/artists/${kino.id}/albums`:
|
||||
return json({ items: [albumSummary] });
|
||||
case `GET /api/v1/artists/${kino.id}/top-tracks`:
|
||||
return json({ items: albumTracks });
|
||||
}
|
||||
if (req.method === 'POST' && /^\/api\/v1\/admin\/users\/[^/]+\/reset-recommendations$/.test(path)) {
|
||||
onboarding.set(path.split('/')[5]!, null);
|
||||
|
||||
Reference in new issue
Block a user