81 lines
2.2 KiB
TypeScript
81 lines
2.2 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import type { LikedTrack, Track } from '$lib/types';
|
|
|
|
function track(id: string): Track {
|
|
return {
|
|
id,
|
|
title: id,
|
|
artist: 'Artist',
|
|
duration: 100,
|
|
explicit: false,
|
|
listensCount: 0
|
|
} as unknown as Track;
|
|
}
|
|
|
|
function likedTrack(id: string): LikedTrack {
|
|
return { ...track(id), likedAt: 1 } as LikedTrack;
|
|
}
|
|
|
|
async function freshStore() {
|
|
vi.resetModules();
|
|
return (await import('./liked.svelte')).liked;
|
|
}
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
describe('liked store', () => {
|
|
it('hydrates only once', async () => {
|
|
const liked = await freshStore();
|
|
liked.hydrate([likedTrack('a')]);
|
|
liked.hydrate([likedTrack('b')]);
|
|
expect(liked.isLiked('a')).toBe(true);
|
|
expect(liked.isLiked('b')).toBe(false);
|
|
expect(liked.count).toBe(1);
|
|
});
|
|
|
|
it('likes and unlikes a track', async () => {
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true }));
|
|
const liked = await freshStore();
|
|
await liked.toggle(track('a'));
|
|
expect(liked.isLiked('a')).toBe(true);
|
|
await liked.toggle(track('a'));
|
|
expect(liked.isLiked('a')).toBe(false);
|
|
expect(fetch).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it('reverts a failed like', async () => {
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: false }));
|
|
const liked = await freshStore();
|
|
await liked.toggle(track('a'));
|
|
expect(liked.isLiked('a')).toBe(false);
|
|
});
|
|
|
|
it('reverts a failed unlike', async () => {
|
|
const liked = await freshStore();
|
|
liked.hydrate([likedTrack('a')]);
|
|
vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('offline')));
|
|
await liked.toggle(track('a'));
|
|
expect(liked.isLiked('a')).toBe(true);
|
|
});
|
|
|
|
it('keeps changes made to other tracks while a request fails', async () => {
|
|
const liked = await freshStore();
|
|
let rejectFirst: (reason: Error) => void = () => {};
|
|
const fetchMock = vi
|
|
.fn()
|
|
.mockImplementationOnce(() => new Promise((_, reject) => (rejectFirst = reject)))
|
|
.mockResolvedValueOnce({ ok: true });
|
|
vi.stubGlobal('fetch', fetchMock);
|
|
|
|
const first = liked.toggle(track('a'));
|
|
await liked.toggle(track('b'));
|
|
rejectFirst(new Error('offline'));
|
|
await first;
|
|
|
|
expect(liked.isLiked('a')).toBe(false);
|
|
expect(liked.isLiked('b')).toBe(true);
|
|
});
|
|
});
|