chore(tests): better typings for factory

This commit is contained in:
Phan An 2024-06-02 02:02:27 +08:00
parent 3d68b1b470
commit bdc9f72368
94 changed files with 569 additions and 389 deletions

View file

@ -71,12 +71,13 @@ export default abstract class UnitTestCase {
}
protected be (user?: User) {
userStore.state.current = user || factory<User>('user')
userStore.state.current = user || factory('user')
return this
}
protected beAdmin () {
return this.be(factory.states('admin')<User>('user'))
factory.states('admin')('user')
return this.be(factory.states('admin')('user'))
}
protected mock<T, M extends MethodOf<Required<T>>> (obj: T, methodName: M, implementation?: any) {

View file

@ -7,6 +7,6 @@ export default (faker: Faker): AlbumInfo => ({
summary: faker.lorem.sentence(),
full: faker.lorem.sentences(4)
},
tracks: factory<AlbumTrack>('album-track', 8),
tracks: factory('album-track', 8),
url: faker.internet.url()
})

View file

@ -0,0 +1,20 @@
import { Faker } from '@faker-js/faker'
export default (faker: Faker): Episode => {
return {
type: 'episodes',
id: faker.datatype.uuid(),
title: faker.lorem.sentence(),
length: faker.datatype.number(),
created_at: faker.date.past().toISOString(),
playback_state: 'Stopped',
liked: false,
play_count: 0,
episode_link: faker.internet.url(),
episode_description: faker.lorem.paragraph(),
episode_image: faker.image.imageUrl(),
podcast_id: faker.datatype.uuid(),
podcast_title: faker.lorem.sentence(),
podcast_author: faker.name.findName()
}
}

View file

@ -1,4 +1,4 @@
import factory from 'factoria'
import factoria, { Factoria } from 'factoria'
import artistFactory, { states as artistStates } from '@/__tests__/factory/artistFactory'
import songFactory, { states as songStates } from '@/__tests__/factory/songFactory'
import albumFactory, { states as albumStates } from '@/__tests__/factory/albumFactory'
@ -14,20 +14,91 @@ import artistInfoFactory from '@/__tests__/factory/artistInfoFactory'
import youTubeVideoFactory from '@/__tests__/factory/youTubeVideoFactory'
import genreFactory from '@/__tests__/factory/genreFactory'
import playlistCollaboratorFactory from '@/__tests__/factory/playlistCollaboratorFactory'
import episodeFactory from '@/__tests__/factory/episodeFactory'
import podcastFactory from '@/__tests__/factory/podcastFactory'
import { Faker } from '@faker-js/faker'
export default factory
.define('artist', faker => artistFactory(faker), artistStates)
.define('artist-info', faker => artistInfoFactory(faker))
.define('album', faker => albumFactory(faker), albumStates)
.define('album-track', faker => albumTrackFactory(faker))
.define('album-info', faker => albumInfoFactory(faker))
.define('song', () => songFactory(), songStates)
.define('interaction', faker => interactionFactory(faker))
.define('genre', faker => genreFactory(faker))
.define('video', faker => youTubeVideoFactory(faker))
.define('smart-playlist-rule', faker => smartPlaylistRuleFactory(faker))
.define('smart-playlist-rule-group', faker => smartPlaylistRuleGroupFactory(faker))
.define('playlist', faker => playlistFactory(faker), playlistStates)
.define('playlist-folder', faker => playlistFolderFactory(faker))
.define('user', faker => userFactory(faker), userStates)
.define('playlist-collaborator', faker => playlistCollaboratorFactory(faker))
type ModelToTypeMap = {
artist: Artist
'artist-info': ArtistInfo
album: Album
'album-track': AlbumTrack
'album-info': AlbumInfo
song: Song
interaction: Interaction
genre: Genre
video: YouTubeVideo
'smart-playlist-rule': SmartPlaylistRule
'smart-playlist-rule-group': SmartPlaylistRuleGroup
playlist: Playlist
'playlist-folder': PlaylistFolder
user: User
'playlist-collaborator': PlaylistCollaborator
episode: Episode
podcast: Podcast
}
type Model = keyof ModelToTypeMap
type Overrides<M extends Model> = Factoria.Overrides<ModelToTypeMap[M]>
const define = <M extends Model>(
model: M,
handle: (faker: Faker) => Overrides<M>,
states?: Record<string, Factoria.StateDefinition>
) => factoria.define(model, handle, states)
function factory <M extends Model>(
model: M,
overrides?: Overrides<M>
): ModelToTypeMap[M]
function factory <M extends Model>(
model: M,
count: 1,
overrides?: Overrides<M>
): ModelToTypeMap[M]
function factory <M extends Model>(
model: M,
count: number,
overrides?: Overrides<M>
): ModelToTypeMap[M][]
function factory <M extends Model>(
model: M,
count: number|Overrides<M> = 1,
overrides?: Overrides<M>
) {
return typeof count === 'number'
? count === 1 ? factoria(model, overrides) : factoria(model, count, overrides)
: factoria(model, count)
}
const states = (...states: string[]): typeof factory => {
factoria.states(...states)
return factory
}
factory.states = states
export default factory as typeof factory & {
states: typeof states
}
define('artist', artistFactory, artistStates)
define('artist-info', artistInfoFactory)
define('album', albumFactory, albumStates)
define('album-track', albumTrackFactory)
define('album-info', albumInfoFactory)
define('song', songFactory, songStates)
define('interaction', interactionFactory)
define('genre', genreFactory)
define('video', youTubeVideoFactory)
define('smart-playlist-rule', smartPlaylistRuleFactory)
define('smart-playlist-rule-group', smartPlaylistRuleGroupFactory)
define('playlist', playlistFactory, playlistStates)
define('playlist-folder', playlistFolderFactory)
define('user', userFactory, userStates)
define('playlist-collaborator', playlistCollaboratorFactory)
define('episode', episodeFactory)
define('podcast', podcastFactory)

View file

@ -18,7 +18,7 @@ export const states: Record<string, (faker: Faker) => Omit<Partial<Playlist>, 't
smart: _ => ({
is_smart: true,
rules: [
factory<SmartPlaylistRuleGroup>('smart-playlist-rule-group')
factory('smart-playlist-rule-group')
]
}),
orphan: _ => ({

View file

@ -0,0 +1,19 @@
import { Faker } from '@faker-js/faker'
export default (faker: Faker): Podcast => {
return {
type: 'podcasts',
id: faker.datatype.uuid(),
title: faker.lorem.sentence(),
url: faker.internet.url(),
link: faker.internet.url(),
image: faker.image.imageUrl(),
description: faker.lorem.paragraph(),
author: faker.name.findName(),
subscribed_at: faker.date.past().toISOString(),
state: {
current_episode: null,
progresses: {}
}
}
}

View file

@ -3,5 +3,5 @@ import factory from 'factoria'
export default (faker: Faker): SmartPlaylistRuleGroup => ({
id: faker.datatype.uuid(),
rules: factory<SmartPlaylistRule>('smart-playlist-rule', 3)
rules: factory('smart-playlist-rule', 3)
})

View file

@ -30,7 +30,7 @@ new class extends UnitTestCase {
})
it('shuffles', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const fetchMock = this.mock(songStore, 'fetchForAlbum').mockResolvedValue(songs)
const shuffleMock = this.mock(playbackService, 'queueAndPlay').mockResolvedValue(void 0)
this.renderComponent()
@ -52,7 +52,7 @@ new class extends UnitTestCase {
}
private renderComponent () {
album = factory<Album>('album', {
album = factory('album', {
id: 42,
name: 'IV',
artist_id: 17,

View file

@ -15,7 +15,7 @@ new class extends UnitTestCase {
it('renders', async () => expect((await this.renderComponent()).html()).toMatchSnapshot())
it('plays all', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const fetchMock = this.mock(songStore, 'fetchForAlbum').mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')
@ -28,7 +28,7 @@ new class extends UnitTestCase {
})
it('shuffles all', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const fetchMock = this.mock(songStore, 'fetchForAlbum').mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')
@ -66,7 +66,7 @@ new class extends UnitTestCase {
})
it('does not have an option to download or go to Unknown Album and Artist', async () => {
await this.renderComponent(factory.states('unknown')<Album>('album'))
await this.renderComponent(factory.states('unknown')('album'))
expect(screen.queryByText('Go to Album')).toBeNull()
expect(screen.queryByText('Go to Artist')).toBeNull()
@ -84,7 +84,7 @@ new class extends UnitTestCase {
}
private async renderComponent (_album?: Album) {
album = _album || factory<Album>('album', {
album = _album || factory('album', {
name: 'IV'
})

View file

@ -29,10 +29,10 @@ new class extends UnitTestCase {
commonStore.state.uses_last_fm = true
if (info === undefined) {
info = factory<AlbumInfo>('album-info')
info = factory('album-info')
}
album = factory<Album>('album', { name: 'IV' })
album = factory('album', { name: 'IV' })
const fetchMock = this.mock(mediaInfoService, 'fetchForAlbum').mockResolvedValue(info)
const rendered = this.render(AlbumInfoComponent, {

View file

@ -8,13 +8,13 @@ import { songStore } from '@/stores'
new class extends UnitTestCase {
protected test () {
it('displays the tracks', async () => {
const album = factory<Album>('album')
const fetchMock = this.mock(songStore, 'fetchForAlbum').mockResolvedValue(factory<Song>('song', 5))
const album = factory('album')
const fetchMock = this.mock(songStore, 'fetchForAlbum').mockResolvedValue(factory('song', 5))
this.render(AlbumTrackList, {
props: {
album,
tracks: factory<AlbumTrack>('album-track', 3)
tracks: factory('album-track', 3)
}
})

View file

@ -13,7 +13,7 @@ new class extends UnitTestCase {
it('renders', () => expect(this.renderComponent().html()).toMatchSnapshot())
it('plays', async () => {
const matchedSong = factory<Song>('song')
const matchedSong = factory('song')
const queueMock = this.mock(queueStore, 'queueIfNotQueued')
const playMock = this.mock(playbackService, 'play')
@ -27,10 +27,10 @@ new class extends UnitTestCase {
}
private renderComponent (matchedSong?: Song) {
const songsToMatchAgainst = factory<Song>('song', 10)
const album = factory<Album>('album')
const songsToMatchAgainst = factory('song', 10)
const album = factory('album')
const track = factory<AlbumTrack>('album-track', {
const track = factory('album-track', {
title: 'Fahrstuhl to Heaven',
length: 280
})

View file

@ -12,7 +12,7 @@ let artist: Artist
new class extends UnitTestCase {
protected beforeEach () {
super.beforeEach(() => {
artist = factory<Artist>('artist', {
artist = factory('artist', {
id: 42,
name: 'Led Zeppelin'
})
@ -38,7 +38,7 @@ new class extends UnitTestCase {
})
it('shuffles', async () => {
const songs = factory<Song>('song', 16)
const songs = factory('song', 16)
const fetchMock = this.mock(songStore, 'fetchForArtist').mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')

View file

@ -15,7 +15,7 @@ new class extends UnitTestCase {
it('renders', async () => expect((await this.renderComponent()).html()).toMatchSnapshot())
it('plays all', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const fetchMock = this.mock(songStore, 'fetchForArtist').mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')
@ -28,7 +28,7 @@ new class extends UnitTestCase {
})
it('shuffles all', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const fetchMock = this.mock(songStore, 'fetchForArtist').mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')
@ -66,14 +66,14 @@ new class extends UnitTestCase {
})
it('does not have an option to download or go to Unknown Artist', async () => {
await this.renderComponent(factory.states('unknown')<Artist>('artist'))
await this.renderComponent(factory.states('unknown')('artist'))
expect(screen.queryByText('Go to Artist')).toBeNull()
expect(screen.queryByText('Download')).toBeNull()
})
it('does not have an option to download or go to Various Artist', async () => {
await this.renderComponent(factory.states('various')<Artist>('artist'))
await this.renderComponent(factory.states('various')('artist'))
expect(screen.queryByText('Go to Artist')).toBeNull()
expect(screen.queryByText('Download')).toBeNull()
@ -81,7 +81,7 @@ new class extends UnitTestCase {
}
private async renderComponent (_artist?: Artist) {
artist = _artist || factory<Artist>('artist', {
artist = _artist || factory('artist', {
name: 'Accept'
})

View file

@ -25,8 +25,8 @@ new class extends UnitTestCase {
private async renderComponent (mode: MediaInfoDisplayMode = 'aside', info?: ArtistInfo) {
commonStore.state.uses_last_fm = true
info = info ?? factory<ArtistInfo>('artist-info')
artist = factory<Artist>('artist', { name: 'Led Zeppelin' })
info = info ?? factory('artist-info')
artist = factory('artist', { name: 'Led Zeppelin' })
const fetchMock = this.mock(mediaInfoService, 'fetchForArtist').mockResolvedValue(info)

View file

@ -9,7 +9,7 @@ new class extends UnitTestCase {
protected test () {
it('accepts invitation', async () => {
const getProspectMock = this.mock(invitationService, 'getUserProspect')
.mockResolvedValue(factory.states('prospect')<User>('user'))
.mockResolvedValue(factory.states('prospect')('user'))
const acceptMock = this.mock(invitationService, 'accept').mockResolvedValue({
token: 'my-api-token',

View file

@ -11,30 +11,38 @@ new class extends UnitTestCase {
it.each<[string, keyof Events, User | Song[] | Playlist | PlaylistFolder | undefined]>([
['add-user-form', 'MODAL_SHOW_ADD_USER_FORM', undefined],
['invite-user-form', 'MODAL_SHOW_INVITE_USER_FORM', undefined],
['edit-user-form', 'MODAL_SHOW_EDIT_USER_FORM', factory<User>('user')],
['edit-song-form', 'MODAL_SHOW_EDIT_SONG_FORM', [factory<Song>('song')]],
['create-playlist-form', 'MODAL_SHOW_CREATE_PLAYLIST_FORM', factory<PlaylistFolder>('playlist-folder')],
['edit-user-form', 'MODAL_SHOW_EDIT_USER_FORM', factory('user')],
['edit-song-form', 'MODAL_SHOW_EDIT_SONG_FORM', [factory('song')]],
['create-playlist-form', 'MODAL_SHOW_CREATE_PLAYLIST_FORM', factory('playlist-folder')],
['create-playlist-folder-form', 'MODAL_SHOW_CREATE_PLAYLIST_FOLDER_FORM', undefined],
['edit-playlist-folder-form', 'MODAL_SHOW_EDIT_PLAYLIST_FOLDER_FORM', factory<PlaylistFolder>('playlist-folder')],
['create-smart-playlist-form', 'MODAL_SHOW_CREATE_SMART_PLAYLIST_FORM', factory<PlaylistFolder>('playlist-folder')],
['edit-playlist-form', 'MODAL_SHOW_EDIT_PLAYLIST_FORM', factory<Playlist>('playlist')],
['edit-smart-playlist-form', 'MODAL_SHOW_EDIT_PLAYLIST_FORM', factory<Playlist>('playlist', { is_smart: true })],
['about-koel', 'MODAL_SHOW_ABOUT_KOEL', undefined]
['edit-playlist-folder-form', 'MODAL_SHOW_EDIT_PLAYLIST_FOLDER_FORM', factory('playlist-folder')],
['playlist-collaboration', 'MODAL_SHOW_PLAYLIST_COLLABORATION', factory('playlist')],
['create-smart-playlist-form', 'MODAL_SHOW_CREATE_SMART_PLAYLIST_FORM', factory('playlist-folder')],
['edit-playlist-form', 'MODAL_SHOW_EDIT_PLAYLIST_FORM', factory('playlist')],
['edit-smart-playlist-form', 'MODAL_SHOW_EDIT_PLAYLIST_FORM', factory('playlist', { is_smart: true })],
['about-koel', 'MODAL_SHOW_ABOUT_KOEL', undefined],
['koel-plus', 'MODAL_SHOW_KOEL_PLUS', undefined],
['equalizer', 'MODAL_SHOW_EQUALIZER', undefined],
['add-podcast-form', 'MODAL_SHOW_ADD_PODCAST_FORM', undefined]
])('shows %s modal', async (modalName, eventName, eventParams?: any) => {
this.render(ModalWrapper, {
global: {
stubs: {
AboutKoelModal: this.stub('about-koel'),
AddPodcastForm: this.stub('add-podcast-form'),
AddUserForm: this.stub('add-user-form'),
EditUserForm: this.stub('edit-user-form'),
InviteUserForm: this.stub('invite-user-form'),
EditSongForm: this.stub('edit-song-form'),
CreatePlaylistForm: this.stub('create-playlist-form'),
CreatePlaylistFolderForm: this.stub('create-playlist-folder-form'),
EditPlaylistFolderForm: this.stub('edit-playlist-folder-form'),
CreatePlaylistForm: this.stub('create-playlist-form'),
CreateSmartPlaylistForm: this.stub('create-smart-playlist-form'),
EditPlaylistFolderForm: this.stub('edit-playlist-folder-form'),
EditPlaylistForm: this.stub('edit-playlist-form'),
EditSmartPlaylistForm: this.stub('edit-smart-playlist-form'),
AboutKoelModal: this.stub('about-koel')
EditSongForm: this.stub('edit-song-form'),
EditUserForm: this.stub('edit-user-form'),
Equalizer: this.stub('equalizer'),
InviteUserForm: this.stub('invite-user-form'),
KoelPlus: this.stub('koel-plus'),
PlaylistCollaborationModal: this.stub('playlist-collaboration')
}
}
})

View file

@ -14,21 +14,21 @@ import { arrayify, eventBus, provideReadonly } from '@/utils'
import { ModalContextKey } from '@/symbols'
const modalNameToComponentMap = {
'create-playlist-form': defineAsyncComponent(() => import('@/components/playlist/CreatePlaylistForm.vue')),
'edit-playlist-form': defineAsyncComponent(() => import('@/components/playlist/EditPlaylistForm.vue')),
'create-smart-playlist-form': defineAsyncComponent(() => import('@/components/playlist/smart-playlist/CreateSmartPlaylistForm.vue')),
'edit-smart-playlist-form': defineAsyncComponent(() => import('@/components/playlist/smart-playlist/EditSmartPlaylistForm.vue')),
'add-user-form': defineAsyncComponent(() => import('@/components/user/AddUserForm.vue')),
'edit-user-form': defineAsyncComponent(() => import('@/components/user/EditUserForm.vue')),
'invite-user-form': defineAsyncComponent(() => import('@/components/user/InviteUserForm.vue')),
'edit-song-form': defineAsyncComponent(() => import('@/components/song/EditSongForm.vue')),
'create-playlist-folder-form': defineAsyncComponent(() => import('@/components/playlist/CreatePlaylistFolderForm.vue')),
'edit-playlist-folder-form': defineAsyncComponent(() => import('@/components/playlist/EditPlaylistFolderForm.vue')),
'playlist-collaboration': defineAsyncComponent(() => import('@/components/playlist/PlaylistCollaborationModal.vue')),
'add-podcast-form': defineAsyncComponent(() => import('@/components/podcast/AddPodcastForm.vue')),
'about-koel': defineAsyncComponent(() => import('@/components/meta/AboutKoelModal.vue')),
'add-podcast-form': defineAsyncComponent(() => import('@/components/podcast/AddPodcastForm.vue')),
'add-user-form': defineAsyncComponent(() => import('@/components/user/AddUserForm.vue')),
'create-playlist-folder-form': defineAsyncComponent(() => import('@/components/playlist/CreatePlaylistFolderForm.vue')),
'create-playlist-form': defineAsyncComponent(() => import('@/components/playlist/CreatePlaylistForm.vue')),
'create-smart-playlist-form': defineAsyncComponent(() => import('@/components/playlist/smart-playlist/CreateSmartPlaylistForm.vue')),
'edit-playlist-folder-form': defineAsyncComponent(() => import('@/components/playlist/EditPlaylistFolderForm.vue')),
'edit-playlist-form': defineAsyncComponent(() => import('@/components/playlist/EditPlaylistForm.vue')),
'edit-smart-playlist-form': defineAsyncComponent(() => import('@/components/playlist/smart-playlist/EditSmartPlaylistForm.vue')),
'edit-song-form': defineAsyncComponent(() => import('@/components/song/EditSongForm.vue')),
'edit-user-form': defineAsyncComponent(() => import('@/components/user/EditUserForm.vue')),
'equalizer': defineAsyncComponent(() => import('@/components/ui/equalizer/Equalizer.vue')),
'invite-user-form': defineAsyncComponent(() => import('@/components/user/InviteUserForm.vue')),
'koel-plus': defineAsyncComponent(() => import('@/components/koel-plus/KoelPlusModal.vue')),
'equalizer': defineAsyncComponent(() => import('@/components/ui/equalizer/Equalizer.vue'))
'playlist-collaboration': defineAsyncComponent(() => import('@/components/playlist/PlaylistCollaborationModal.vue'))
}
type ModalName = keyof typeof modalNameToComponentMap

View file

@ -33,7 +33,7 @@ new class extends UnitTestCase {
private renderComponent (song?: Song | null) {
if (song === undefined) {
song = factory<Song>('song', {
song = factory('song', {
id: '00000000-0000-0000-0000-000000000000',
title: 'Fahrstuhl to Heaven',
artist_name: 'Led Zeppelin',

View file

@ -10,7 +10,7 @@ new class extends UnitTestCase {
it('renders with no current song', () => expect(this.render(FooterSongInfo).html()).toMatchSnapshot())
it('renders with current song', () => {
const song = factory<Song>('song', {
const song = factory('song', {
title: 'Fahrstuhl zum Mond',
album_cover: 'https://via.placeholder.com/150',
playback_state: 'Playing',

View file

@ -31,7 +31,7 @@ new class extends UnitTestCase {
return this.render(MainContent, {
global: {
provide: {
[<symbol>CurrentPlayableKey]: ref(factory<Song>('song'))
[<symbol>CurrentPlayableKey]: ref(factory('song'))
},
stubs: {
AlbumArtOverlay,

View file

@ -14,7 +14,7 @@ new class extends UnitTestCase {
it('sets the active tab to the preference', async () => {
preferenceStore.active_extra_panel_tab = 'YouTube'
this.renderComponent(ref(factory<Song>('song')))
this.renderComponent(ref(factory('song')))
const tab = screen.getByTestId<HTMLElement>('extra-drawer-youtube')
expect(tab.style.display).toBe('none')
@ -25,7 +25,7 @@ new class extends UnitTestCase {
it('fetches info for the current song', async () => {
commonStore.state.uses_you_tube = true
const song = factory<Song>('song')
const song = factory('song')
const songRef = ref<Song | null>(null)
const [, resolveArtistMock, resolveAlbumMock] = this.renderComponent(songRef)
@ -66,10 +66,10 @@ new class extends UnitTestCase {
}
private renderComponent (songRef: Ref<Song | null> = ref(null)): [RenderResult, Mock, Mock] {
const artist = factory<Artist>('artist')
const artist = factory('artist')
const resolveArtistMock = this.mock(artistStore, 'resolve').mockResolvedValue(artist)
const album = factory<Album>('album')
const album = factory('album')
const resolveAlbumMock = this.mock(albumStore, 'resolve').mockResolvedValue(album)
const rendered = this.render(ExtraDrawer, {

View file

@ -17,7 +17,7 @@ new class extends UnitTestCase {
protected test () {
it('requests context menu if is playlist', async () => {
const emitMock = this.mock(eventBus, 'emit')
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
this.renderComponent(playlist)
await fireEvent.contextMenu(screen.getByRole('listitem'))

View file

@ -11,9 +11,9 @@ new class extends UnitTestCase {
protected test () {
it('displays orphan playlists', () => {
playlistStore.state.playlists = [
factory.states('orphan')<Playlist>('playlist', { name: 'Foo Playlist' }),
factory.states('orphan')<Playlist>('playlist', { name: 'Bar Playlist' }),
factory.states('smart', 'orphan')<Playlist>('playlist', { name: 'Smart Playlist' })
factory.states('orphan')('playlist', { name: 'Foo Playlist' }),
factory.states('orphan')('playlist', { name: 'Bar Playlist' }),
factory.states('smart', 'orphan')('playlist', { name: 'Smart Playlist' })
]
this.renderComponent()
@ -25,8 +25,8 @@ new class extends UnitTestCase {
it('displays playlist folders', () => {
playlistFolderStore.state.folders = [
factory<PlaylistFolder>('playlist-folder', { name: 'Foo Folder' }),
factory<PlaylistFolder>('playlist-folder', { name: 'Bar Folder' })
factory('playlist-folder', { name: 'Foo Folder' }),
factory('playlist-folder', { name: 'Bar Folder' })
]
this.renderComponent()

View file

@ -9,7 +9,7 @@ new class extends UnitTestCase {
protected test () {
it('submits', async () => {
const storeMock = this.mock(playlistFolderStore, 'store')
.mockResolvedValue(factory<PlaylistFolder>('playlist-folder'))
.mockResolvedValue(factory('playlist-folder'))
this.render(CreatePlaylistFolderForm)

View file

@ -10,8 +10,8 @@ import CreatePlaylistForm from './CreatePlaylistForm.vue'
new class extends UnitTestCase {
protected test () {
it('creates playlist with no songs', async () => {
const folder = factory<PlaylistFolder>('playlist-folder')
const storeMock = this.mock(playlistStore, 'store').mockResolvedValue(factory<Playlist>('playlist'))
const folder = factory('playlist-folder')
const storeMock = this.mock(playlistStore, 'store').mockResolvedValue(factory('playlist'))
this.render(CreatePlaylistForm, {
global: {
@ -32,9 +32,9 @@ new class extends UnitTestCase {
})
it('creates playlist with songs', async () => {
const songs = factory<Song>('song', 3)
const folder = factory<PlaylistFolder>('playlist-folder')
const storeMock = this.mock(playlistStore, 'store').mockResolvedValue(factory<Playlist>('playlist'))
const songs = factory('song', 3)
const folder = factory('playlist-folder')
const storeMock = this.mock(playlistStore, 'store').mockResolvedValue(factory('playlist'))
this.render(CreatePlaylistForm, {
global: {

View file

@ -10,7 +10,7 @@ import EditPlaylistFolderForm from './EditPlaylistFolderForm.vue'
new class extends UnitTestCase {
protected test () {
it('submits', async () => {
const folder = factory<PlaylistFolder>('playlist-folder', { name: 'My folder' })
const folder = factory('playlist-folder', { name: 'My folder' })
const renameMock = this.mock(playlistFolderStore, 'rename')
this.render(EditPlaylistFolderForm, {
global: {

View file

@ -10,9 +10,9 @@ import EditPlaylistForm from './EditPlaylistForm.vue'
new class extends UnitTestCase {
protected test () {
it('submits', async () => {
playlistFolderStore.state.folders = factory<PlaylistFolder>('playlist-folder', 3)
playlistFolderStore.state.folders = factory('playlist-folder', 3)
const playlist = factory<Playlist>('playlist', {
const playlist = factory('playlist', {
name: 'My playlist',
folder_id: playlistFolderStore.state.folders[0].id
})

View file

@ -10,7 +10,7 @@ new class extends UnitTestCase {
it('works', async () => {
this.mock(playlistCollaborationService, 'createInviteLink').mockResolvedValue('http://localhost:3000/invite/1234')
const writeTextMock = this.mock(navigator.clipboard, 'writeText')
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
this.render(Component, {
props: {

View file

@ -11,7 +11,7 @@ new class extends UnitTestCase {
const { html } = this.render(Modal, {
global: {
provide: {
[<symbol>ModalContextKey]: [ref({ playlist: factory<Playlist>('playlist') })]
[<symbol>ModalContextKey]: [ref({ playlist: factory('playlist') })]
},
stubs: {
InviteCollaborators: this.stub('InviteCollaborators'),

View file

@ -1,5 +1,10 @@
<template>
<div class="collaboration-modal max-w-[640px]" tabindex="0" @keydown.esc="close">
<div
class="collaboration-modal max-w-[640px]"
tabindex="0"
@keydown.esc="close"
data-testid="playlist-collaboration"
>
<header>
<h1>Playlist Collaboration</h1>
</header>

View file

@ -7,12 +7,12 @@ import Component from './PlaylistCollaboratorList.vue'
new class extends UnitTestCase {
protected test () {
it('renders', async () => {
const playlist = factory<Playlist>('playlist', {
const playlist = factory('playlist', {
is_collaborative: true
})
const fetchMock = this.mock(playlistCollaborationService, 'fetchCollaborators').mockResolvedValue(
factory<PlaylistCollaborator>('playlist-collaborator', 5)
factory('playlist-collaborator', 5)
)
const { html } = await this.be().renderComponent(playlist)

View file

@ -7,9 +7,9 @@ import Component from './PlaylistCollaboratorListItem.vue'
new class extends UnitTestCase {
protected test () {
it('does not show a badge when current user is not the collaborator', async () => {
const currentUser = factory<User>('user')
const currentUser = factory('user')
this.be(currentUser).renderComponent({
collaborator: factory<PlaylistCollaborator>('playlist-collaborator', { id: currentUser.id + 1 }),
collaborator: factory('playlist-collaborator', { id: currentUser.id + 1 }),
removable: true,
manageable: true,
role: 'owner'
@ -19,9 +19,9 @@ new class extends UnitTestCase {
})
it('shows a badge when current user is the collaborator', async () => {
const currentUser = factory<User>('user')
const currentUser = factory('user')
this.be(currentUser).renderComponent({
collaborator: factory<PlaylistCollaborator>('playlist-collaborator',
collaborator: factory('playlist-collaborator',
{
id: currentUser.id,
name: currentUser.name,
@ -37,7 +37,7 @@ new class extends UnitTestCase {
})
it('shows the role', async () => {
const collaborator = factory<PlaylistCollaborator>('playlist-collaborator')
const collaborator = factory('playlist-collaborator')
this.be().renderComponent({
collaborator,
@ -59,7 +59,7 @@ new class extends UnitTestCase {
})
it('emits the remove event when the remove button is clicked', async () => {
const collaborator = factory<PlaylistCollaborator>('playlist-collaborator')
const collaborator = factory('playlist-collaborator')
const { emitted } = this.be().renderComponent({
collaborator,
removable: true,

View file

@ -12,7 +12,7 @@ import PlaylistContextMenu from './PlaylistContextMenu.vue'
new class extends UnitTestCase {
protected test () {
it('edits a standard playlist', async () => {
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
await this.renderComponent(playlist)
const emitMock = this.mock(eventBus, 'emit')
@ -22,7 +22,7 @@ new class extends UnitTestCase {
})
it('edits a smart playlist', async () => {
const playlist = factory.states('smart')<Playlist>('playlist')
const playlist = factory.states('smart')('playlist')
await this.renderComponent(playlist)
const emitMock = this.mock(eventBus, 'emit')
@ -32,7 +32,7 @@ new class extends UnitTestCase {
})
it('deletes a playlist', async () => {
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
await this.renderComponent(playlist)
const emitMock = this.mock(eventBus, 'emit')
@ -42,8 +42,8 @@ new class extends UnitTestCase {
})
it('plays', async () => {
const playlist = factory<Playlist>('playlist')
const songs = factory<Song>('song', 3)
const playlist = factory('playlist')
const songs = factory('song', 3)
const fetchMock = this.mock(songStore, 'fetchForPlaylist').mockResolvedValue(songs)
const queueMock = this.mock(playbackService, 'queueAndPlay')
const goMock = this.mock(Router, 'go')
@ -59,7 +59,7 @@ new class extends UnitTestCase {
})
it('warns if attempting to play an empty playlist', async () => {
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
const fetchMock = this.mock(songStore, 'fetchForPlaylist').mockResolvedValue([])
const queueMock = this.mock(playbackService, 'queueAndPlay')
const goMock = this.mock(Router, 'go')
@ -78,8 +78,8 @@ new class extends UnitTestCase {
})
it('shuffles', async () => {
const playlist = factory<Playlist>('playlist')
const songs = factory<Song>('song', 3)
const playlist = factory('playlist')
const songs = factory('song', 3)
const fetchMock = this.mock(songStore, 'fetchForPlaylist').mockResolvedValue(songs)
const queueMock = this.mock(playbackService, 'queueAndPlay')
const goMock = this.mock(Router, 'go')
@ -95,7 +95,7 @@ new class extends UnitTestCase {
})
it('warns if attempting to shuffle an empty playlist', async () => {
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
const fetchMock = this.mock(songStore, 'fetchForPlaylist').mockResolvedValue([])
const queueMock = this.mock(playbackService, 'queueAndPlay')
const goMock = this.mock(Router, 'go')
@ -114,8 +114,8 @@ new class extends UnitTestCase {
})
it('queues', async () => {
const playlist = factory<Playlist>('playlist')
const songs = factory<Song>('song', 3)
const playlist = factory('playlist')
const songs = factory('song', 3)
const fetchMock = this.mock(songStore, 'fetchForPlaylist').mockResolvedValue(songs)
const queueMock = this.mock(queueStore, 'queueAfterCurrent')
const toastMock = this.mock(MessageToasterStub.value, 'success')
@ -131,8 +131,8 @@ new class extends UnitTestCase {
})
it('does not have an option to edit or delete if the playlist is not owned by the current user', async () => {
const user = factory<User>('user')
const playlist = factory<Playlist>('playlist', {
const user = factory('user')
const playlist = factory('playlist', {
user_id: user.id + 1
})
@ -144,7 +144,7 @@ new class extends UnitTestCase {
it('opens collaboration form', async () => {
this.enablePlusEdition()
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
await this.renderComponent(playlist)
const emitMock = this.mock(eventBus, 'emit')
@ -155,7 +155,7 @@ new class extends UnitTestCase {
}
private async renderComponent (playlist: Playlist, user: User | null = null) {
userStore.state.current = user || factory<User>('user', {
userStore.state.current = user || factory('user', {
id: playlist.user_id
})

View file

@ -12,7 +12,7 @@ import PlaylistFolderContextMenu from './PlaylistFolderContextMenu.vue'
new class extends UnitTestCase {
protected test () {
it('renames', async () => {
const folder = factory<PlaylistFolder>('playlist-folder')
const folder = factory('playlist-folder')
await this.renderComponent(folder)
const emitMock = this.mock(eventBus, 'emit')
@ -22,7 +22,7 @@ new class extends UnitTestCase {
})
it('deletes', async () => {
const folder = factory<PlaylistFolder>('playlist-folder')
const folder = factory('playlist-folder')
await this.renderComponent(folder)
const emitMock = this.mock(eventBus, 'emit')
@ -33,7 +33,7 @@ new class extends UnitTestCase {
it('plays', async () => {
const folder = this.createPlayableFolder()
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const fetchMock = this.mock(songStore, 'fetchForPlaylistFolder').mockResolvedValue(songs)
const queueMock = this.mock(playbackService, 'queueAndPlay')
const goMock = this.mock(Router, 'go')
@ -70,7 +70,7 @@ new class extends UnitTestCase {
it('shuffles', async () => {
const folder = this.createPlayableFolder()
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const fetchMock = this.mock(songStore, 'fetchForPlaylistFolder').mockResolvedValue(songs)
const queueMock = this.mock(playbackService, 'queueAndPlay')
const goMock = this.mock(Router, 'go')
@ -86,7 +86,7 @@ new class extends UnitTestCase {
})
it('does not show shuffle option if folder is empty', async () => {
const folder = factory<PlaylistFolder>('playlist-folder')
const folder = factory('playlist-folder')
await this.renderComponent(folder)
expect(screen.queryByText('Shuffle All')).toBeNull()
@ -121,8 +121,8 @@ new class extends UnitTestCase {
}
private createPlayableFolder () {
const folder = factory<PlaylistFolder>('playlist-folder')
this.mock(playlistStore, 'byFolder', factory<Playlist>('playlist', 3, { folder_id: folder.id }))
const folder = factory('playlist-folder')
this.mock(playlistStore, 'byFolder', factory('playlist', 3, { folder_id: folder.id }))
return folder
}
}

View file

@ -1,5 +1,5 @@
<template>
<FormBase>
<FormBase data-testid="edit-smart-playlist-form">
<form @submit.prevent="submit" @keydown.esc="maybeClose">
<header>
<h1>Edit Smart Playlist</h1>

View file

@ -0,0 +1,18 @@
import { screen } from '@testing-library/vue'
import { expect, it } from 'vitest'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { podcastStore } from '@/stores'
import Component from './AddPodcastForm.vue'
import factory from '@/__tests__/factory'
new class extends UnitTestCase {
protected test () {
it('adds a new podcast', async() => {
const storeMock = this.mock(podcastStore, 'store').mockResolvedValue(factory('podcast'))
this.render(Component)
await this.type(screen.getByPlaceholderText('https://example.com/feed.xml'), 'https://foo.bar/feed.xml')
await this.user.click(screen.getByRole('button', { name: 'Save' }))
expect(storeMock).toHaveBeenCalledWith('https://foo.bar/feed.xml')
})
}
}

View file

@ -0,0 +1,38 @@
import { screen } from '@testing-library/vue'
import { expect, it } from 'vitest'
import UnitTestCase from '@/__tests__/UnitTestCase'
import Component from './EpisodeItem.vue'
import factory from '@/__tests__/factory'
import { playbackService } from '@/services'
new class extends UnitTestCase {
private renderComponent (episode: Episode, podcast?: Podcast) {
podcast = podcast || factory('podcast', {
id: episode.id
})
this.render(Component, {
props: {
episode,
podcast
}
})
}
protected test () {
it('pauses playback', async () => {
const pauseMock = this.mock(playbackService, 'pause')
const episode = factory('episode', {
id: 'foo',
playback_state: 'Playing'
})
this.renderComponent(episode)
await this.user.click(screen.getByRole('button'))
expect(pauseMock).toHaveBeenCalled()
})
}
}

View file

@ -12,7 +12,7 @@ new class extends UnitTestCase {
const updateMock = this.mock(authService, 'updateProfile')
const alertMock = this.mock(MessageToasterStub.value, 'success')
this.renderComponent(factory<User>('user', {
this.renderComponent(factory('user', {
avatar: 'https://gravatar.com/foo'
}))

View file

@ -43,7 +43,7 @@ new class extends UnitTestCase {
}
private async renderComponent () {
albumStore.state.albums = factory<Album>('album', 9)
albumStore.state.albums = factory('album', 9)
this.render(AlbumListScreen, {
global: {

View file

@ -40,7 +40,7 @@ new class extends UnitTestCase {
})
it('shows other albums from the same artist', async () => {
const albums = factory<Album>('album', 3)
const albums = factory('album', 3)
albums.push(album)
const fetchMock = this.mock(albumStore, 'fetchForArtist').mockResolvedValue(albums)
await this.renderComponent()
@ -57,7 +57,7 @@ new class extends UnitTestCase {
private async renderComponent () {
commonStore.state.uses_last_fm = true
album = factory<Album>('album', {
album = factory('album', {
id: 42,
name: 'Led Zeppelin IV',
artist_id: 123,
@ -66,7 +66,7 @@ new class extends UnitTestCase {
const resolveAlbumMock = this.mock(albumStore, 'resolve').mockResolvedValue(album)
const songs = factory<Song>('song', 13)
const songs = factory('song', 13)
const fetchSongsMock = this.mock(songStore, 'fetchForAlbum').mockResolvedValue(songs)
await this.router.activateRoute({

View file

@ -12,7 +12,7 @@ new class extends UnitTestCase {
super.beforeEach(cb)
commonStore.state.song_count = 420
commonStore.state.song_length = 123_456
songStore.state.songs = factory<Song>('song', 20)
songStore.state.songs = factory('song', 20)
this.be()
}

View file

@ -43,7 +43,7 @@ new class extends UnitTestCase {
}
private async renderComponent () {
artistStore.state.artists = factory<Artist>('artist', 9)
artistStore.state.artists = factory('artist', 9)
const rendered = this.render(ArtistListScreen, {
global: {

View file

@ -14,14 +14,14 @@ new class extends UnitTestCase {
protected async renderComponent () {
commonStore.state.uses_last_fm = true
artist = factory<Artist>('artist', {
artist = factory('artist', {
id: 42,
name: 'Led Zeppelin',
})
const resolveArtistMock = this.mock(artistStore, 'resolve').mockResolvedValue(artist)
const songs = factory<Song>('song', 13)
const songs = factory('song', 13)
const fetchSongsMock = this.mock(songStore, 'fetchForArtist').mockResolvedValue(songs)
await this.router.activateRoute({

View file

@ -8,7 +8,7 @@ import FavoritesScreen from './FavoritesScreen.vue'
new class extends UnitTestCase {
protected test () {
it('renders a list of favorites', async () => {
favoriteStore.state.songs = factory<Song>('song', 13)
favoriteStore.state.songs = factory('song', 13)
await this.renderComponent()
await waitFor(() => {

View file

@ -10,9 +10,9 @@ new class extends UnitTestCase {
it('renders the list of genres and their song counts', async () => {
// ensure there's no duplicated names
const genres = [
factory<Genre>('genre', { name: 'Rock', song_count: 10 }),
factory<Genre>('genre', { name: 'Pop', song_count: 20 }),
factory<Genre>('genre', { name: 'Jazz', song_count: 30 })
factory('genre', { name: 'Rock', song_count: 10 }),
factory('genre', { name: 'Pop', song_count: 20 }),
factory('genre', { name: 'Jazz', song_count: 30 })
]
const fetchMock = this.mock(genreStore, 'fetchAll').mockResolvedValue(genres)

View file

@ -14,8 +14,8 @@ new class extends UnitTestCase {
})
it('shuffles all songs without fetching if genre has <= 500 songs', async () => {
const genre = factory<Genre>('genre', { song_count: 10 })
const songs = factory<Song>('song', 10)
const genre = factory('genre', { song_count: 10 })
const songs = factory('song', 10)
const playbackMock = this.mock(playbackService, 'queueAndPlay')
await this.renderComponent(genre, songs)
@ -26,8 +26,8 @@ new class extends UnitTestCase {
})
it('fetches and shuffles all songs if genre has > 500 songs', async () => {
const genre = factory<Genre>('genre', { song_count: 501 })
const songs = factory<Song>('song', 10) // we don't really need to generate 501 songs
const genre = factory('genre', { song_count: 501 })
const songs = factory('song', 10) // we don't really need to generate 501 songs
const playbackMock = this.mock(playbackService, 'queueAndPlay')
const fetchMock = this.mock(songStore, 'fetchRandomForGenre').mockResolvedValue(songs)
@ -43,12 +43,12 @@ new class extends UnitTestCase {
}
private async renderComponent (genre?: Genre, songs?: Song[]) {
genre = genre || factory<Genre>('genre')
genre = genre || factory('genre')
const fetchGenreMock = this.mock(genreStore, 'fetchOne').mockResolvedValue(genre)
const paginateMock = this.mock(songStore, 'paginateForGenre').mockResolvedValue({
nextPage: 2,
songs: songs || factory<Song>('song', 13)
songs: songs || factory('song', 13)
})
await this.router.activateRoute({

View file

@ -12,7 +12,7 @@ let playlist: Playlist
new class extends UnitTestCase {
protected test () {
it('renders the playlist', async () => {
await this.renderComponent(factory<Song>('song', 10))
await this.renderComponent(factory('song', 10))
await waitFor(() => {
screen.getByTestId('song-list')
@ -31,7 +31,7 @@ new class extends UnitTestCase {
it('downloads the playlist', async () => {
const downloadMock = this.mock(downloadService, 'fromPlaylist')
await this.renderComponent(factory<Song>('song', 10))
await this.renderComponent(factory('song', 10))
await this.tick(2)
await this.user.click(screen.getByRole('button', { name: 'Download All' }))
@ -58,7 +58,7 @@ new class extends UnitTestCase {
}
private async renderComponent (songs: Song[]) {
playlist = playlist || factory<Playlist>('playlist')
playlist = playlist || factory('playlist')
playlistStore.init([playlist])
playlist.songs = songs

View file

@ -9,7 +9,7 @@ import QueueScreen from './QueueScreen.vue'
new class extends UnitTestCase {
protected test () {
it('renders the queue', () => {
this.renderComponent(factory<Song>('song', 3))
this.renderComponent(factory('song', 3))
expect(screen.queryByTestId('song-list')).toBeTruthy()
expect(screen.queryByTestId('screen-empty-state')).toBeNull()
@ -37,7 +37,7 @@ new class extends UnitTestCase {
})
it('Shuffles all', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
this.renderComponent(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')

View file

@ -8,7 +8,7 @@ import RecentlyPlayedScreen from './RecentlyPlayedScreen.vue'
new class extends UnitTestCase {
protected test () {
it('displays the songs', async () => {
await this.renderComponent(factory<Song>('song', 3))
await this.renderComponent(factory('song', 3))
screen.getByTestId('song-list')
expect(screen.queryByTestId('screen-empty-state')).toBeNull()

View file

@ -24,7 +24,7 @@ new class extends UnitTestCase {
})
it('displays a list of user prospects', async () => {
const users = [...factory.states('prospect')<User>('user', 2), ...factory<User>('user', 3)]
const users = [...factory.states('prospect')('user', 2), ...factory('user', 3)]
await this.renderComponent(users)
expect(screen.getAllByTestId('user-card')).toHaveLength(5)
@ -52,7 +52,7 @@ new class extends UnitTestCase {
private async renderComponent (users: User[] = []) {
if (users.length === 0) {
users = factory<User>('user', 6)
users = factory('user', 6)
}
const fetchMock = this.mock(http, 'get').mockResolvedValue(users)

View file

@ -7,7 +7,7 @@ import MostPlayedAlbums from './MostPlayedAlbums.vue'
new class extends UnitTestCase {
protected test () {
it('displays the albums', () => {
overviewStore.state.mostPlayedAlbums = factory<Album>('album', 6)
overviewStore.state.mostPlayedAlbums = factory('album', 6)
expect(this.render(MostPlayedAlbums, {
global: {
stubs: {

View file

@ -7,7 +7,7 @@ import MostPlayedArtists from './MostPlayedArtists.vue'
new class extends UnitTestCase {
protected test () {
it('displays the artists', () => {
overviewStore.state.mostPlayedArtists = factory<Artist>('artist', 6)
overviewStore.state.mostPlayedArtists = factory('artist', 6)
expect(this.render(MostPlayedArtists, {
global: {
stubs: {

View file

@ -7,7 +7,7 @@ import MostPlayedSongs from './MostPlayedSongs.vue'
new class extends UnitTestCase {
protected test () {
it('displays the songs', () => {
overviewStore.state.mostPlayedSongs = factory<Song>('song', 6)
overviewStore.state.mostPlayedSongs = factory('song', 6)
expect(this.render(MostPlayedSongs, {
global: {
stubs: {

View file

@ -7,7 +7,7 @@ import RecentlyAddedAlbums from './RecentlyAddedAlbums.vue'
new class extends UnitTestCase {
protected test () {
it('displays the albums', () => {
overviewStore.state.recentlyAddedAlbums = factory<Album>('album', 6)
overviewStore.state.recentlyAddedAlbums = factory('album', 6)
expect(this.render(RecentlyAddedAlbums, {
global: {
stubs: {

View file

@ -7,7 +7,7 @@ import RecentlyAddedSongs from './RecentlyAddedSongs.vue'
new class extends UnitTestCase {
protected test () {
it('displays the songs', () => {
overviewStore.state.recentlyAddedSongs = factory<Song>('song', 6)
overviewStore.state.recentlyAddedSongs = factory('song', 6)
expect(this.render(RecentlyAddedSongs, {
global: {
stubs: {

View file

@ -9,7 +9,7 @@ import RecentlyPlayedSongs from './RecentlyPlayedSongs.vue'
new class extends UnitTestCase {
protected test () {
it('displays the songs', () => {
overviewStore.state.recentlyPlayed = factory<Song>('song', 6)
overviewStore.state.recentlyPlayed = factory('song', 6)
expect(this.render(RecentlyPlayedSongs, {
global: {
stubs: {

View file

@ -19,9 +19,9 @@ new class extends UnitTestCase {
protected test () {
it('renders', () => {
playlistStore.state.playlists = [
factory<Playlist>('playlist', { name: 'Foo' }),
factory<Playlist>('playlist', { name: 'Bar' }),
factory<Playlist>('playlist', { name: 'Baz' })
factory('playlist', { name: 'Foo' }),
factory('playlist', { name: 'Bar' }),
factory('playlist', { name: 'Baz' })
]
expect(this.renderComponent().html()).toMatchSnapshot()
@ -40,7 +40,7 @@ new class extends UnitTestCase {
['to top', 'queue-top', 'queueToTop'],
['to bottom', 'queue-bottom', 'queue']
])('queues songs %s', async (_: string, testId: string, queueMethod: MethodOf<typeof queueStore>) => {
queueStore.state.playables = factory<Song>('song', 5)
queueStore.state.playables = factory('song', 5)
queueStore.state.playables[2].playback_state = 'Playing'
const mock = this.mock(queueStore, queueMethod)
@ -62,7 +62,7 @@ new class extends UnitTestCase {
it('adds songs to existing playlist', async () => {
const mock = this.mock(playlistStore, 'addContent')
playlistStore.state.playlists = factory<Playlist>('playlist', 3)
playlistStore.state.playlists = factory('playlist', 3)
this.renderComponent()
await this.user.click(screen.getAllByTestId('add-to-playlist')[1])
@ -81,7 +81,7 @@ new class extends UnitTestCase {
}
private renderComponent (customConfig: Partial<AddToMenuConfig> = {}) {
songs = factory<Song>('song', 5)
songs = factory('song', 5)
return this.render(AddToMenu, {
props: {

View file

@ -28,7 +28,7 @@ new class extends UnitTestCase {
const emitMock = this.mock(eventBus, 'emit')
const alertMock = this.mock(MessageToasterStub.value, 'success')
const { html } = await this.renderComponent(factory<Song>('song', {
const { html } = await this.renderComponent(factory('song', {
title: 'Rocket to Heaven',
artist_name: 'Led Zeppelin',
album_name: 'IV',
@ -81,7 +81,7 @@ new class extends UnitTestCase {
const emitMock = this.mock(eventBus, 'emit')
const alertMock = this.mock(MessageToasterStub.value, 'success')
const { html } = await this.renderComponent(factory<Song>('song', 3))
const { html } = await this.renderComponent(factory('song', 3))
expect(html()).toMatchSnapshot()
expect(screen.queryByTestId('title-input')).toBeNull()
@ -112,7 +112,7 @@ new class extends UnitTestCase {
})
it('displays artist name if all songs have the same artist', async () => {
await this.renderComponent(factory<Song>('song', 4, {
await this.renderComponent(factory('song', 4, {
artist_id: 1000,
artist_name: 'Led Zeppelin',
album_id: 1001,

View file

@ -20,7 +20,7 @@ new class extends UnitTestCase {
it('queues and plays', async () => {
const queueMock = this.mock(queueStore, 'queueIfNotQueued')
const playMock = this.mock(playbackService, 'play')
const song = factory<Song>('song', { playback_state: 'Stopped' })
const song = factory('song', { playback_state: 'Stopped' })
await this.renderComponent(song)
await this.user.click(screen.getByText('Play'))
@ -31,7 +31,7 @@ new class extends UnitTestCase {
it('pauses playback', async () => {
const pauseMock = this.mock(playbackService, 'pause')
await this.renderComponent(factory<Song>('song', { playback_state: 'Playing' }))
await this.renderComponent(factory('song', { playback_state: 'Playing' }))
await this.user.click(screen.getByText('Pause'))
@ -40,7 +40,7 @@ new class extends UnitTestCase {
it('resumes playback', async () => {
const resumeMock = this.mock(playbackService, 'resume')
await this.renderComponent(factory<Song>('song', { playback_state: 'Paused' }))
await this.renderComponent(factory('song', { playback_state: 'Paused' }))
await this.user.click(screen.getByText('Play'))
@ -49,7 +49,7 @@ new class extends UnitTestCase {
it('goes to album details screen', async () => {
const goMock = this.mock(Router, 'go')
await this.renderComponent(factory<Song>('song'))
await this.renderComponent(factory('song'))
await this.user.click(screen.getByText('Go to Album'))
@ -58,7 +58,7 @@ new class extends UnitTestCase {
it('goes to artist details screen', async () => {
const goMock = this.mock(Router, 'go')
await this.renderComponent(factory<Song>('song'))
await this.renderComponent(factory('song'))
await this.user.click(screen.getByText('Go to Artist'))
@ -178,7 +178,7 @@ new class extends UnitTestCase {
})
it('lists and adds to existing playlist', async () => {
playlistStore.state.playlists = factory<Playlist>('playlist', 3)
playlistStore.state.playlists = factory('playlist', 3)
const addMock = this.mock(playlistStore, 'addContent')
this.mock(MessageToasterStub.value, 'success')
await this.renderComponent()
@ -191,8 +191,8 @@ new class extends UnitTestCase {
})
it('does not list smart playlists', async () => {
playlistStore.state.playlists = factory<Playlist>('playlist', 3)
playlistStore.state.playlists.push(factory.states('smart')<Playlist>('playlist', { name: 'My Smart Playlist' }))
playlistStore.state.playlists = factory('playlist', 3)
playlistStore.state.playlists.push(factory.states('smart')('playlist', { name: 'My Smart Playlist' }))
await this.renderComponent()
@ -200,7 +200,7 @@ new class extends UnitTestCase {
})
it('removes from playlist', async () => {
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
playlistStore.state.playlists.push(playlist)
await this.router.activateRoute({
@ -248,21 +248,21 @@ new class extends UnitTestCase {
})
it('has an option to copy shareable URL in Community edition', async () => {
await this.renderComponent(factory<Song>('song'))
await this.renderComponent(factory('song'))
screen.getByText('Copy Shareable URL')
})
it('has an option to copy shareable URL if song is public in Plus edition', async () => {
this.enablePlusEdition()
await this.renderComponent(factory<Song>('song', { is_public: true }))
await this.renderComponent(factory('song', { is_public: true }))
screen.getByText('Copy Shareable URL')
})
it('does not have an option to share if song is private in Plus edition', async () => {
this.enablePlusEdition()
await this.renderComponent(factory<Song>('song', { is_public: false }))
await this.renderComponent(factory('song', { is_public: false }))
expect(screen.queryByText('Copy Shareable URL')).toBeNull()
})
@ -303,8 +303,8 @@ new class extends UnitTestCase {
it('makes songs private', async () => {
this.enablePlusEdition()
const user = factory<User>('user')
const songs = factory<Song>('song', 5, {
const user = factory('user')
const songs = factory('song', 5, {
is_public: true,
owner_id: user.id
})
@ -320,8 +320,8 @@ new class extends UnitTestCase {
it('makes songs public', async () => {
this.enablePlusEdition()
const user = factory<User>('user')
const songs = factory<Song>('song', 5, {
const user = factory('user')
const songs = factory('song', 5, {
is_public: false,
owner_id: user.id
})
@ -337,9 +337,9 @@ new class extends UnitTestCase {
it('does not have an option to make songs public or private if current user is not owner', async () => {
this.enablePlusEdition()
const user = factory<User>('user')
const owner = factory<User>('user')
const songs = factory<Song>('song', 5, {
const user = factory('user')
const owner = factory('user')
const songs = factory('song', 5, {
is_public: false,
owner_id: owner.id
})
@ -353,11 +353,11 @@ new class extends UnitTestCase {
it('has both options to make public and private if songs have mixed visibilities', async () => {
this.enablePlusEdition()
const owner = factory<User>('user')
const songs = factory<Song>('song', 2, {
const owner = factory('user')
const songs = factory('song', 2, {
is_public: false,
owner_id: owner.id
}).concat(...factory<Song>('song', 3, {
}).concat(...factory('song', 3, {
is_public: true,
owner_id: owner.id
}))
@ -369,8 +369,8 @@ new class extends UnitTestCase {
})
it('does not have an option to make songs public or private or Community edition', async () => {
const owner = factory<User>('user')
const songs = factory<Song>('song', 5, {
const owner = factory('user')
const songs = factory('song', 5, {
is_public: false,
owner_id: owner.id
})
@ -383,7 +383,7 @@ new class extends UnitTestCase {
}
private async renderComponent (_songs?: Song | Song[]) {
songs = arrayify(_songs || factory<Song>('song', 5))
songs = arrayify(_songs || factory('song', 5))
const rendered = this.render(PlayableContextMenu)
eventBus.emit('PLAYABLE_CONTEXT_MENU_REQUESTED', { pageX: 420, pageY: 42 } as MouseEvent, songs)
@ -393,7 +393,7 @@ new class extends UnitTestCase {
}
private fillQueue () {
queueStore.state.playables = factory<Song>('song', 5)
queueStore.state.playables = factory('song', 5)
queueStore.state.playables[2].playback_state = 'Playing'
}
}

View file

@ -29,7 +29,7 @@ new class extends UnitTestCase {
}
private renderComponent (playbackState: PlaybackState = 'Stopped') {
song = factory<Song>('song', {
song = factory('song', {
playback_state: playbackState,
play_count: 10,
title: 'Foo bar'

View file

@ -12,7 +12,7 @@ new class extends UnitTestCase {
['Like Foo by Bar', false]
])('%s', async (name: string, liked: boolean) => {
const mock = this.mock(favoriteStore, 'toggleOne')
const song = factory<Song>('song', {
const song = factory('song', {
liked,
title: 'Foo',
artist_name: 'Bar'

View file

@ -19,7 +19,7 @@ let songs: Playable[]
new class extends UnitTestCase {
protected test () {
it('renders', async () => {
const { html } = await this.renderComponent(factory<Song>('song', 5))
const { html } = await this.renderComponent(factory('song', 5))
expect(html()).toMatchSnapshot()
})
@ -29,7 +29,7 @@ new class extends UnitTestCase {
['album_name', 'header-album'],
['length', 'header-length']
])('sorts by %s upon %s clicked', async (field, testId) => {
const { emitted } = await this.renderComponent(factory<Song>('song', 5))
const { emitted } = await this.renderComponent(factory('song', 5))
await this.user.click(screen.getByTestId(testId))
expect(emitted().sort[0]).toEqual([field, 'desc'])
@ -39,7 +39,7 @@ new class extends UnitTestCase {
})
it('cannot be sorted if configured so', async () => {
const { emitted } = await this.renderComponent(factory<Song>('song', 5), {
const { emitted } = await this.renderComponent(factory('song', 5), {
sortable: false,
reorderable: true
})

View file

@ -63,7 +63,7 @@ new class extends UnitTestCase {
}
private renderComponent (selectedSongCount = 1, configOverrides: Partial<SongListControlsConfig> = {}) {
const songs = factory<Song>('song', 5)
const songs = factory('song', 5)
const config: SongListControlsConfig = merge({
addTo: {
queue: true,

View file

@ -9,7 +9,7 @@ let row: PlayableRow
new class extends UnitTestCase {
protected test () {
it('renders', async () => {
const song = factory<Song>('song', {
const song = factory('song', {
title: 'Test Song',
album_name: 'Test Album',
artist_name: 'Test Artist',
@ -32,7 +32,7 @@ new class extends UnitTestCase {
}
private renderComponent (song?: Song) {
song = song ?? factory<Song>('song')
song = song ?? factory('song')
row = {
playable: song,

View file

@ -26,7 +26,7 @@ new class extends UnitTestCase {
}
private renderComponent (playbackState: PlaybackState = 'Stopped') {
song = factory<Song>('song', {
song = factory('song', {
playback_state: playbackState,
play_count: 10,
title: 'Foo bar'

View file

@ -13,7 +13,7 @@ new class extends UnitTestCase {
protected test () {
it('toggles the playback of current song', async () => {
const toggleMock = this.mock(playbackService, 'toggle')
this.renderComponent(factory<Song>('song'))
this.renderComponent(factory('song'))
await this.user.click(screen.getByRole('button'))
@ -26,7 +26,7 @@ new class extends UnitTestCase {
['Playlist', 'fetchForPlaylist', '71d8cd40-20d4-4b17-b460-d30fe5bb7b66']
])('initiates playback for %s screen', async (screenName, fetchMethod, id) => {
commonStore.state.song_count = 10
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const fetchMock = this.mock(songStore, fetchMethod).mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')
const goMock = this.mock(Router, 'go')
@ -55,7 +55,7 @@ new class extends UnitTestCase {
['RecentlyPlayed', recentlyPlayedStore, 'fetch']
])('initiates playback for %s screen', async (screenName, store, fetchMethod) => {
commonStore.state.song_count = 10
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const fetchMock = this.mock(store, fetchMethod).mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')
const goMock = this.mock(Router, 'go')
@ -77,7 +77,7 @@ new class extends UnitTestCase {
it.each<[ScreenName]>([['Queue'], ['Songs'], ['Albums']])('initiates playback %s screen', async screenName => {
commonStore.state.song_count = 10
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const fetchMock = this.mock(queueStore, 'fetchRandom').mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')
const goMock = this.mock(Router, 'go')

View file

@ -11,7 +11,7 @@ new class extends UnitTestCase {
it('renders', () => expect(this.renderComponent().html()).toMatchSnapshot())
it('provides a button to add lyrics if current user is admin', async () => {
const song = factory<Song>('song', { lyrics: null })
const song = factory('song', { lyrics: null })
const mock = this.mock(eventBus, 'emit')
this.beAdmin().renderComponent(song)
@ -22,13 +22,13 @@ new class extends UnitTestCase {
})
it('does not have a button to add lyrics if current user is not an admin', async () => {
this.be().renderComponent(factory<Song>('song', { lyrics: null }))
this.be().renderComponent(factory('song', { lyrics: null }))
expect(screen.queryByRole('button', { name: 'Click here' })).toBeNull()
})
}
private renderComponent (song?: Song) {
song = song || factory<Song>('song', {
song = song || factory('song', {
lyrics: 'Foo bar baz qux'
})

View file

@ -6,7 +6,7 @@ import ProfileAvatar from './ProfileAvatar.vue'
new class extends UnitTestCase {
protected test () {
it('renders', () => {
const user = factory<User>('user', {
const user = factory('user', {
name: 'John Doe',
avatar: 'https://example.com/avatar.jpg'
})

View file

@ -9,7 +9,7 @@ new class extends UnitTestCase {
it('emits events on user actions', async () => {
const { emitted } = this.render(ArtistAlbumCard, {
props: {
entity: factory<Album>('album')
entity: factory('album')
}
})

View file

@ -21,7 +21,7 @@ new class extends UnitTestCase {
})
it('plays album', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const fetchMock = this.mock(songStore, 'fetchForAlbum').mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')
this.renderForAlbum()
@ -35,7 +35,7 @@ new class extends UnitTestCase {
})
it('queues album', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const fetchMock = this.mock(songStore, 'fetchForAlbum').mockResolvedValue(songs)
const queueMock = this.mock(queueStore, 'queue')
this.renderForAlbum()
@ -51,7 +51,7 @@ new class extends UnitTestCase {
})
it('plays artist', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const fetchMock = this.mock(songStore, 'fetchForArtist').mockResolvedValue(songs)
const playMock = this.mock(playbackService, 'queueAndPlay')
this.renderForArtist()
@ -65,7 +65,7 @@ new class extends UnitTestCase {
})
it('queues artist', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const fetchMock = this.mock(songStore, 'fetchForArtist').mockResolvedValue(songs)
const queueMock = this.mock(queueStore, 'queue')
this.renderForArtist()
@ -82,7 +82,7 @@ new class extends UnitTestCase {
}
private renderForAlbum () {
album = factory<Album>('album', {
album = factory('album', {
name: 'IV',
cover: 'https://test/album.jpg'
})
@ -95,7 +95,7 @@ new class extends UnitTestCase {
}
private renderForArtist () {
artist = factory<Artist>('artist', {
artist = factory('artist', {
name: 'Led Zeppelin',
image: 'https://test/blimp.jpg'
})

View file

@ -10,14 +10,14 @@ import YouTubeVideoList from './YouTubeVideoList.vue'
new class extends UnitTestCase {
protected test () {
it('functions', async () => {
const song = factory<Song>('song')
const song = factory('song')
const searchMock = this.mock(youTubeService, 'searchVideosBySong').mockResolvedValueOnce({
nextPageToken: 'foo',
items: factory<YouTubeVideo>('video', 5)
items: factory('video', 5)
}).mockResolvedValueOnce({
nextPageToken: 'bar',
items: factory<YouTubeVideo>('video', 3)
items: factory('video', 3)
})
this.render(YouTubeVideoList, {

View file

@ -14,7 +14,7 @@ new class extends UnitTestCase {
const updateMock = this.mock(userStore, 'update')
const alertMock = this.mock(MessageToasterStub.value, 'success')
const user = ref(factory<User>('user', { name: 'John Doe' }))
const user = ref(factory('user', { name: 'John Doe' }))
this.render(EditUserForm, {
global: {

View file

@ -12,7 +12,7 @@ import UserCard from './UserCard.vue'
new class extends UnitTestCase {
protected test () {
it('has different behaviors for current user', () => {
const user = factory<User>('user')
const user = factory('user')
this.be(user).renderComponent(user)
screen.getByTitle('This is you!')
@ -20,7 +20,7 @@ new class extends UnitTestCase {
})
it('edits user', async () => {
const user = factory<User>('user')
const user = factory('user')
const emitMock = this.mock(eventBus, 'emit')
this.renderComponent(user)
@ -31,7 +31,7 @@ new class extends UnitTestCase {
it('redirects to Profile screen if edit current user', async () => {
const mock = this.mock(Router, 'go')
const user = factory<User>('user')
const user = factory('user')
this.be(user).renderComponent(user)
await this.user.click(screen.getByRole('button', { name: 'Your Profile' }))
@ -41,7 +41,7 @@ new class extends UnitTestCase {
it('deletes user if confirmed', async () => {
this.mock(DialogBoxStub.value, 'confirm').mockResolvedValue(true)
const user = factory<User>('user')
const user = factory('user')
this.beAdmin().renderComponent(user)
const destroyMock = this.mock(userStore, 'destroy')
@ -52,7 +52,7 @@ new class extends UnitTestCase {
it('does not delete user if not confirmed', async () => {
this.mock(DialogBoxStub.value, 'confirm').mockResolvedValue(false)
const user = factory<User>('user')
const user = factory('user')
this.beAdmin().renderComponent(user)
const destroyMock = this.mock(userStore, 'destroy')
@ -63,7 +63,7 @@ new class extends UnitTestCase {
it('revokes invite for prospects', async () => {
this.mock(DialogBoxStub.value, 'confirm').mockResolvedValue(true)
const prospect = factory.states('prospect')<User>('user')
const prospect = factory.states('prospect')('user')
this.beAdmin().renderComponent(prospect)
const revokeMock = this.mock(invitationService, 'revoke')
@ -74,7 +74,7 @@ new class extends UnitTestCase {
it('does not revoke invite for prospects if not confirmed', async () => {
this.mock(DialogBoxStub.value, 'confirm').mockResolvedValue(false)
const prospect = factory.states('prospect')<User>('user')
const prospect = factory.states('prospect')('user')
this.beAdmin().renderComponent(prospect)
const revokeMock = this.mock(invitationService, 'revoke')

View file

@ -56,13 +56,13 @@ new class extends UnitTestCase {
})
it('updates profile', async () => {
userStore.state.current = factory<User>('user', {
userStore.state.current = factory('user', {
id: 1,
name: 'John Doe',
email: 'john@doe.com'
})
const updated = factory<User>('user', {
const updated = factory('user', {
id: 1,
name: 'Jane Doe',
email: 'jane@doe.com'

View file

@ -8,35 +8,35 @@ new class extends UnitTestCase {
protected test () {
it('downloads songs', () => {
const mock = this.mock(downloadService, 'trigger')
downloadService.fromPlayables([factory<Song>('song', { id: 'foo' }), factory<Song>('song', { id: 'bar' })])
downloadService.fromPlayables([factory('song', { id: 'bar' })])
expect(mock).toHaveBeenCalledWith('songs?songs[]=bar&songs[]=foo&')
})
it('downloads all by artist', () => {
const mock = this.mock(downloadService, 'trigger')
downloadService.fromArtist(factory<Artist>('artist', { id: 42 }))
downloadService.fromArtist(factory('artist', { id: 42 }))
expect(mock).toHaveBeenCalledWith('artist/42')
})
it('downloads all in album', () => {
const mock = this.mock(downloadService, 'trigger')
downloadService.fromAlbum(factory<Album>('album', { id: 42 }))
downloadService.fromAlbum(factory('album', { id: 42 }))
expect(mock).toHaveBeenCalledWith('album/42')
})
it('downloads a playlist', () => {
const mock = this.mock(downloadService, 'trigger')
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
downloadService.fromPlaylist(playlist)
expect(mock).toHaveBeenCalledWith(`playlist/${playlist.id}`)
})
it.each<[Song[], boolean]>([[[], false], [factory<Song>('song', 5), true]])(
it.each<[Song[], boolean]>([[[], false], [factory('song', 5), true]])(
'downloads favorites if available',
(songs, triggered) => {
const mock = this.mock(downloadService, 'trigger')

View file

@ -29,7 +29,7 @@ new class extends UnitTestCase {
})
it('invites users', async () => {
const prospects = factory.states('prospect')<User>('user', 2)
const prospects = factory.states('prospect')('user', 2)
const addMock = this.mock(userStore, 'add')
const postMock = this.mock(http, 'post').mockResolvedValue(prospects)
@ -44,7 +44,7 @@ new class extends UnitTestCase {
})
it('revokes an invitation', async () => {
const user = factory.states('prospect')<User>('user')
const user = factory.states('prospect')('user')
const removeMock = this.mock(userStore, 'remove')
const deleteMock = this.mock(http, 'delete')

View file

@ -8,8 +8,8 @@ import { mediaInfoService } from './mediaInfoService'
new class extends UnitTestCase {
protected test () {
it('fetches the artist info', async () => {
const artist = artistStore.syncWithVault(factory<Artist>('artist', { id: 42 }))[0]
const artistInfo = factory<ArtistInfo>('artist-info')
const artist = artistStore.syncWithVault(factory('artist', { id: 42 }))[0]
const artistInfo = factory('artist-info')
const getMock = this.mock(http, 'get').mockResolvedValue(artistInfo)
const hasCacheMock = this.mock(cache, 'has', false)
const setCacheMock = this.mock(cache, 'set')
@ -23,20 +23,20 @@ new class extends UnitTestCase {
})
it('gets the artist info from cache', async () => {
const artistInfo = factory<ArtistInfo>('artist-info')
const artistInfo = factory('artist-info')
const hasCacheMock = this.mock(cache, 'has', true)
const getCacheMock = this.mock(cache, 'get', artistInfo)
const getMock = this.mock(http, 'get')
expect(await mediaInfoService.fetchForArtist(factory<Artist>('artist', { id: 42 }))).toBe(artistInfo)
expect(await mediaInfoService.fetchForArtist(factory('artist', { id: 42 }))).toBe(artistInfo)
expect(hasCacheMock).toHaveBeenCalledWith(['artist.info', 42])
expect(getCacheMock).toHaveBeenCalledWith(['artist.info', 42])
expect(getMock).not.toHaveBeenCalled()
})
it('fetches the album info', async () => {
const album = albumStore.syncWithVault(factory<Album>('album', { id: 42 }))[0]
const albumInfo = factory<AlbumInfo>('album-info')
const album = albumStore.syncWithVault(factory('album', { id: 42 }))[0]
const albumInfo = factory('album-info')
const getMock = this.mock(http, 'get').mockResolvedValue(albumInfo)
const hasCacheMock = this.mock(cache, 'has', false)
const setCacheMock = this.mock(cache, 'set')
@ -50,12 +50,12 @@ new class extends UnitTestCase {
})
it('gets the album info from cache', async () => {
const albumInfo = factory<AlbumInfo>('album-info')
const albumInfo = factory('album-info')
const hasCacheMock = this.mock(cache, 'has', true)
const getCacheMock = this.mock(cache, 'get', albumInfo)
const getMock = this.mock(http, 'get')
expect(await mediaInfoService.fetchForAlbum(factory<Album>('album', { id: 42 }))).toBe(albumInfo)
expect(await mediaInfoService.fetchForAlbum(factory('album', { id: 42 }))).toBe(albumInfo)
expect(hasCacheMock).toHaveBeenCalledWith(['album.info', 42])
expect(getCacheMock).toHaveBeenCalledWith(['album.info', 42])
expect(getMock).not.toHaveBeenCalled()

View file

@ -41,7 +41,7 @@ new class extends UnitTestCase {
])(
'when playCountRegistered is %s, isTranscoding is %s, current media time is %d, media duration is %d, then registerPlay() should be call %d times',
(playCountRegistered, isTranscoding, currentTime, duration, numberOfCalls) => {
const song = factory<Song>('song', {
const song = factory('song', {
play_count_registered: playCountRegistered,
playback_state: 'Playing'
})
@ -78,7 +78,7 @@ new class extends UnitTestCase {
it('scrobbles if current song ends', () => {
commonStore.state.uses_last_fm = true
userStore.state.current = reactive(factory<User>('user', {
userStore.state.current = reactive(factory('user', {
preferences: {
lastfm_session_key: 'foo'
}
@ -115,7 +115,7 @@ new class extends UnitTestCase {
(preloaded, isTranscoding, currentTime, duration, numberOfCalls) => {
this.mock(playbackService, 'registerPlay')
this.setReadOnlyProperty(queueStore, 'next', factory<Song>('song', { preloaded }))
this.setReadOnlyProperty(queueStore, 'next', factory('song', { preloaded }))
this.setReadOnlyProperty(playbackService, 'isTranscoding', isTranscoding)
playbackService.init(document.querySelector('.plyr')!)
@ -136,7 +136,7 @@ new class extends UnitTestCase {
it('registers play', () => {
const recentlyPlayedStoreAddMock = this.mock(recentlyPlayedStore, 'add')
const registerPlayMock = this.mock(songStore, 'registerPlay')
const song = factory<Song>('song')
const song = factory('song')
playbackService.registerPlay(song)
@ -155,7 +155,7 @@ new class extends UnitTestCase {
const createElementMock = this.mock(document, 'createElement', audioElement)
this.mock(songStore, 'getSourceUrl').mockReturnValue('/foo?token=o5afd')
const song = factory<Song>('song')
const song = factory('song')
playbackService.preload(song)
@ -298,7 +298,7 @@ new class extends UnitTestCase {
})
it('resumes playback', async () => {
const song = this.setCurrentSong(factory<Song>('song', {
const song = this.setCurrentSong(factory('song', {
playback_state: 'Paused'
}))
@ -329,7 +329,7 @@ new class extends UnitTestCase {
])('%ss playback if toggled when current song playback state is %s', async (action, playbackState) => {
playbackService.init(document.querySelector('.plyr')!)
this.setCurrentSong(factory<Song>('song', { playback_state: playbackState }))
this.setCurrentSong(factory('song', { playback_state: playbackState }))
const actionMock = this.mock(playbackService, action)
await playbackService.toggle()
@ -339,7 +339,7 @@ new class extends UnitTestCase {
it('queues and plays songs without shuffling', async () => {
playbackService.init(document.querySelector('.plyr')!)
const songs = factory<Song>('song', 5)
const songs = factory('song', 5)
const replaceQueueMock = this.mock(queueStore, 'replaceQueueWith')
const playMock = this.mock(playbackService, 'play')
const firstSongInQueue = songs[0]
@ -357,8 +357,8 @@ new class extends UnitTestCase {
it('queues and plays songs with shuffling', async () => {
playbackService.init(document.querySelector('.plyr')!)
const songs = factory<Song>('song', 5)
const shuffledSongs = factory<Song>('song', 5)
const songs = factory('song', 5)
const shuffledSongs = factory('song', 5)
const replaceQueueMock = this.mock(queueStore, 'replaceQueueWith')
const playMock = this.mock(playbackService, 'play')
const firstSongInQueue = songs[0]
@ -376,7 +376,7 @@ new class extends UnitTestCase {
it('plays first song in queue', async () => {
playbackService.init(document.querySelector('.plyr')!)
const songs = factory<Song>('song', 5)
const songs = factory('song', 5)
queueStore.state.playables = songs
this.setReadOnlyProperty(queueStore, 'first', songs[0])
const playMock = this.mock(playbackService, 'play')
@ -400,7 +400,7 @@ new class extends UnitTestCase {
}
private setCurrentSong (song?: Song) {
song = reactive(song || factory<Song>('song', {
song = reactive(song || factory('song', {
playback_state: 'Playing'
}))

View file

@ -7,7 +7,7 @@ import { playlistCollaborationService as service } from './playlistCollaboration
new class extends UnitTestCase {
protected test () {
it('creates invite link', async () => {
const playlist = factory<Playlist>('playlist', { is_smart: false })
const playlist = factory('playlist', { is_smart: false })
const postMock = this.mock(http, 'post').mockResolvedValue({ token: 'abc123' })
const link = await service.createInviteLink(playlist)
@ -17,7 +17,7 @@ new class extends UnitTestCase {
})
it('throws if trying to create invite link for smart playlist', async () => {
const playlist = factory<Playlist>('playlist', { is_smart: true })
const playlist = factory('playlist', { is_smart: true })
await expect(service.createInviteLink(playlist)).rejects.toThrow('Smart playlists are not collaborative.')
})
@ -31,8 +31,8 @@ new class extends UnitTestCase {
})
it('fetches collaborators', async () => {
const playlist = factory<Playlist>('playlist')
const collaborators = factory<PlaylistCollaborator[]>('playlist-collaborator', 2)
const playlist = factory('playlist')
const collaborators = factory('playlist-collaborator', 2)
const getMock = this.mock(http, 'get').mockResolvedValue(collaborators)
const received = await service.fetchCollaborators(playlist)
@ -42,8 +42,8 @@ new class extends UnitTestCase {
})
it('removes collaborator', async () => {
const playlist = factory<Playlist>('playlist')
const collaborator = factory<PlaylistCollaborator>('playlist-collaborator')
const playlist = factory('playlist')
const collaborator = factory('playlist-collaborator')
const deleteMock = this.mock(http, 'delete').mockResolvedValue({})
const removeCacheMock = this.mock(cache, 'remove')

View file

@ -7,7 +7,7 @@ import { youTubeService } from './youTubeService'
new class extends UnitTestCase {
protected test () {
it('plays a video', () => {
const video = factory<YouTubeVideo>('video', {
const video = factory('video', {
id: {
videoId: 'foo'
},

View file

@ -14,13 +14,13 @@ new class extends UnitTestCase {
protected test () {
it('gets an album by ID', () => {
const album = factory<Album>('album')
const album = factory('album')
albumStore.vault.set(album.id, album)
expect(albumStore.byId(album.id)).toEqual(album)
})
it('removes albums by IDs', () => {
const albums = factory<Album>('album', 3)
const albums = factory('album', 3)
albums.forEach(album => albumStore.vault.set(album.id, album))
albumStore.state.albums = albums
@ -33,15 +33,15 @@ new class extends UnitTestCase {
})
it('identifies an unknown album', () => {
const album = factory.states('unknown')<Album>('album')
const album = factory.states('unknown')('album')
expect(albumStore.isUnknown(album)).toBe(true)
expect(albumStore.isUnknown(album.id)).toBe(true)
expect(albumStore.isUnknown(factory<Album>('album'))).toBe(false)
expect(albumStore.isUnknown(factory('album'))).toBe(false)
})
it('syncs albums with the vault', () => {
const album = factory<Album>('album', { name: 'IV' })
const album = factory('album', { name: 'IV' })
albumStore.syncWithVault(album)
expect(albumStore.vault.get(album.id)).toEqual(album)
@ -54,9 +54,9 @@ new class extends UnitTestCase {
})
it('uploads a cover for an album', async () => {
const album = factory<Album>('album')
const album = factory('album')
albumStore.syncWithVault(album)
const songsInAlbum = factory<Song>('song', 3, { album_id: album.id })
const songsInAlbum = factory('song', 3, { album_id: album.id })
const putMock = this.mock(http, 'put').mockResolvedValue({ cover_url: 'http://test/cover.jpg' })
this.mock(songStore, 'byAlbum', songsInAlbum)
@ -70,7 +70,7 @@ new class extends UnitTestCase {
it('fetches an album thumbnail', async () => {
const getMock = this.mock(http, 'get').mockResolvedValue({ thumbnailUrl: 'http://test/thumbnail.jpg' })
const album = factory<Album>('album')
const album = factory('album')
const url = await albumStore.fetchThumbnail(album.id)
@ -79,7 +79,7 @@ new class extends UnitTestCase {
})
it('resolves an album', async () => {
const album = factory<Album>('album')
const album = factory('album')
const getMock = this.mock(http, 'get').mockResolvedValueOnce(album)
expect(await albumStore.resolve(album.id)).toEqual(album)
@ -91,7 +91,7 @@ new class extends UnitTestCase {
})
it('paginates', async () => {
const albums = factory<Album>('album', 3)
const albums = factory('album', 3)
this.mock(http, 'get').mockResolvedValueOnce({
data: albums,

View file

@ -14,13 +14,13 @@ new class extends UnitTestCase {
protected test () {
it('gets an artist by ID', () => {
const artist = factory<Artist>('artist')
const artist = factory('artist')
artistStore.vault.set(artist.id, artist)
expect(artistStore.byId(artist.id)).toEqual(artist)
})
it('removes artists by IDs', () => {
const artists = factory<Artist>('artist', 3)
const artists = factory('artist', 3)
artists.forEach(artist => artistStore.vault.set(artist.id, artist))
artistStore.state.artists = artists
@ -33,29 +33,29 @@ new class extends UnitTestCase {
})
it('identifies an unknown artist', () => {
const artist = factory.states('unknown')<Artist>('artist')
const artist = factory.states('unknown')('artist')
expect(artistStore.isUnknown(artist)).toBe(true)
expect(artistStore.isUnknown(artist.id)).toBe(true)
expect(artistStore.isUnknown(factory<Artist>('artist'))).toBe(false)
expect(artistStore.isUnknown(factory('artist'))).toBe(false)
})
it('identifies the various artist', () => {
const artist = factory.states('various')<Artist>('artist')
const artist = factory.states('various')('artist')
expect(artistStore.isVarious(artist)).toBe(true)
expect(artistStore.isVarious(artist.id)).toBe(true)
expect(artistStore.isVarious(factory<Artist>('artist'))).toBe(false)
expect(artistStore.isVarious(factory('artist'))).toBe(false)
})
it('identifies a standard artist', () => {
expect(artistStore.isStandard(factory.states('unknown')<Artist>('artist'))).toBe(false)
expect(artistStore.isStandard(factory.states('various')<Artist>('artist'))).toBe(false)
expect(artistStore.isStandard(factory<Artist>('artist'))).toBe(true)
expect(artistStore.isStandard(factory.states('unknown')('artist'))).toBe(false)
expect(artistStore.isStandard(factory.states('various')('artist'))).toBe(false)
expect(artistStore.isStandard(factory('artist'))).toBe(true)
})
it('syncs artists with the vault', () => {
const artist = factory<Artist>('artist', { name: 'Led Zeppelin' })
const artist = factory('artist', { name: 'Led Zeppelin' })
artistStore.syncWithVault(artist)
expect(artistStore.vault.get(artist.id)).toEqual(artist)
@ -68,7 +68,7 @@ new class extends UnitTestCase {
})
it('uploads an image for an artist', async () => {
const artist = factory<Artist>('artist')
const artist = factory('artist')
artistStore.syncWithVault(artist)
const putMock = this.mock(http, 'put').mockResolvedValue({ image_url: 'http://test/img.jpg' })
@ -80,7 +80,7 @@ new class extends UnitTestCase {
})
it('resolves an artist', async () => {
const artist = factory<Artist>('artist')
const artist = factory('artist')
const getMock = this.mock(http, 'get').mockResolvedValueOnce(artist)
expect(await artistStore.resolve(artist.id)).toEqual(artist)
@ -92,7 +92,7 @@ new class extends UnitTestCase {
})
it('paginates', async () => {
const artists = factory<Artist>('artist', 3)
const artists = factory('artist', 3)
this.mock(http, 'get').mockResolvedValueOnce({
data: artists,

View file

@ -14,7 +14,7 @@ new class extends UnitTestCase {
const addMock = this.mock(favoriteStore, 'add')
const removeMock = this.mock(favoriteStore, 'remove')
const postMock = this.mock(http, 'post')
const song = factory<Song>('song', { liked: false })
const song = factory('song', { liked: false })
await favoriteStore.toggleOne(song)
@ -29,7 +29,7 @@ new class extends UnitTestCase {
})
it('adds songs', () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
favoriteStore.add(songs)
expect(favoriteStore.state.songs).toEqual(songs)
@ -39,14 +39,14 @@ new class extends UnitTestCase {
})
it('removes songs', () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
favoriteStore.state.songs = songs
favoriteStore.remove(songs)
expect(favoriteStore.state.songs).toEqual([])
})
it('likes several songs', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const addMock = this.mock(favoriteStore, 'add')
const postMock = this.mock(http, 'post')
@ -57,7 +57,7 @@ new class extends UnitTestCase {
})
it('unlikes several songs', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const removeMock = this.mock(favoriteStore, 'remove')
const postMock = this.mock(http, 'post')
@ -68,7 +68,7 @@ new class extends UnitTestCase {
})
it('fetches favorites', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const getMock = this.mock(http, 'get').mockResolvedValue(songs)
await favoriteStore.fetch()

View file

@ -7,14 +7,14 @@ import { genreStore } from '@/stores/genreStore'
new class extends UnitTestCase {
protected test () {
it('fetches all genres', async () => {
const genres = factory<Genre>('genre', 3)
const genres = factory('genre', 3)
this.mock(http, 'get').mockResolvedValue(genres)
expect(await genreStore.fetchAll()).toEqual(genres)
})
it('fetches a single genre', async () => {
const genre = factory<Genre>('genre')
const genre = factory('genre')
this.mock(http, 'get').mockResolvedValue(genre)
expect(await genreStore.fetchOne(genre.name)).toEqual(genre)

View file

@ -25,12 +25,12 @@ new class extends UnitTestCase {
const artistSyncMock = this.mock(artistStore, 'syncWithVault')
const refreshMock = this.mock(overviewStore, 'refreshPlayStats')
const mostPlayedSongs = factory<Song>('song', 7)
const mostPlayedAlbums = factory<Album>('album', 6)
const mostPlayedArtists = factory<Artist>('artist', 6)
const recentlyAddedSongs = factory<Song>('song', 9)
const recentlyAddedAlbums = factory<Album>('album', 6)
const recentlyPlayedSongs = factory<Song>('song', 9)
const mostPlayedSongs = factory('song', 7)
const mostPlayedAlbums = factory('album', 6)
const mostPlayedArtists = factory('artist', 6)
const recentlyAddedSongs = factory('song', 9)
const recentlyAddedAlbums = factory('album', 6)
const recentlyPlayedSongs = factory('song', 9)
const getMock = this.mock(http, 'get').mockResolvedValueOnce({
most_played_songs: mostPlayedSongs,
@ -54,8 +54,8 @@ new class extends UnitTestCase {
})
it('refreshes the store', () => {
const mostPlayedSongs = factory<Song>('song', 7)
const recentlyPlayedSongs = factory<Song>('song', 9)
const mostPlayedSongs = factory('song', 7)
const recentlyPlayedSongs = factory('song', 9)
const mostPlayedSongsMock = this.mock(songStore, 'getMostPlayed', mostPlayedSongs)
recentlyPlayedStore.excerptState.playables = recentlyPlayedSongs

View file

@ -69,7 +69,7 @@ new class extends UnitTestCase {
})
it('sets up a smart playlist with properly unserialized rules', () => {
const playlist = factory<Playlist>('playlist', {
const playlist = factory('playlist', {
is_smart: true,
rules: serializedRuleGroups as unknown as SmartPlaylistRuleGroup[]
})
@ -80,9 +80,9 @@ new class extends UnitTestCase {
})
it('stores a playlist', async () => {
const songs = factory<Song>('song', 3)
const playlist = factory<Playlist>('playlist')
const folder = factory<PlaylistFolder>('playlist-folder')
const songs = factory('song', 3)
const playlist = factory('playlist')
const folder = factory('playlist-folder')
const postMock = this.mock(http, 'post').mockResolvedValue(playlist)
this.mock(playlistStore, 'serializeSmartPlaylistRulesForStorage', null)
@ -99,9 +99,9 @@ new class extends UnitTestCase {
})
it('deletes a playlist', async () => {
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
const deleteMock = this.mock(http, 'delete')
playlistStore.state.playlists = [factory<Playlist>('playlist'), playlist]
playlistStore.state.playlists = [factory('playlist'), playlist]
await playlistStore.delete(playlist)
@ -111,8 +111,8 @@ new class extends UnitTestCase {
})
it('adds songs to a playlist', async () => {
const playlist = factory<Playlist>('playlist')
const songs = factory<Song>('song', 3)
const playlist = factory('playlist')
const songs = factory('song', 3)
const postMock = this.mock(http, 'post').mockResolvedValue(playlist)
const removeMock = this.mock(cache, 'remove')
@ -126,8 +126,8 @@ new class extends UnitTestCase {
})
it('removes songs from a playlist', async () => {
const playlist = factory<Playlist>('playlist')
const songs = factory<Song>('song', 3)
const playlist = factory('playlist')
const songs = factory('song', 3)
const deleteMock = this.mock(http, 'delete').mockResolvedValue(playlist)
const removeMock = this.mock(cache, 'remove')
@ -141,20 +141,20 @@ new class extends UnitTestCase {
})
it('does not modify a smart playlist content', async () => {
const playlist = factory.states('smart')<Playlist>('playlist')
const playlist = factory.states('smart')('playlist')
const postMock = this.mock(http, 'post')
await playlistStore.addContent(playlist, factory<Song>('song', 3))
await playlistStore.addContent(playlist, factory('song', 3))
expect(postMock).not.toHaveBeenCalled()
await playlistStore.removeContent(playlist, factory<Song>('song', 3))
await playlistStore.removeContent(playlist, factory('song', 3))
expect(postMock).not.toHaveBeenCalled()
})
it('updates a standard playlist', async () => {
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
playlistStore.state.playlists = [playlist]
const folder = factory<PlaylistFolder>('playlist-folder')
const folder = factory('playlist-folder')
const putMock = this.mock(http, 'put').mockResolvedValue(playlist)
@ -170,9 +170,9 @@ new class extends UnitTestCase {
})
it('updates a smart playlist', async () => {
const playlist = factory.states('smart')<Playlist>('playlist')
const playlist = factory.states('smart')('playlist')
playlistStore.state.playlists = [playlist]
const rules = factory<SmartPlaylistRuleGroup>('smart-playlist-rule-group', 2)
const rules = factory('smart-playlist-rule-group', 2)
const serializeMock = this.mock(playlistStore, 'serializeSmartPlaylistRulesForStorage', ['Whatever'])
const putMock = this.mock(http, 'put').mockResolvedValue(playlist)
const removeMock = this.mock(cache, 'remove')
@ -191,7 +191,7 @@ new class extends UnitTestCase {
})
it('uploads a cover for a playlist', async () => {
const playlist = factory<Playlist>('playlist')
const playlist = factory('playlist')
playlistStore.state.playlists = [playlist]
const putMock = this.mock(http, 'put').mockResolvedValue({ cover_url: 'http://test/cover.jpg' })

View file

@ -11,7 +11,7 @@ new class extends UnitTestCase {
protected test () {
it('sets preferences and saves the state', () => {
const user = factory<User>('user')
const user = factory('user')
user.preferences = defaultPreferences
const mock = this.mock(http, 'patch')
preferenceStore.set('volume', 5)

View file

@ -10,7 +10,7 @@ let songs: Song[]
new class extends UnitTestCase {
protected beforeEach () {
super.beforeEach(() => {
songs = factory<Song>('song', 3)
songs = factory('song', 3)
queueStore.state.playables = reactive(songs)
})
}
@ -23,7 +23,7 @@ new class extends UnitTestCase {
it('returns the last queued song', () => expect(queueStore.last).toEqual(songs[2]))
it('queues to bottom', () => {
const song = factory<Song>('song')
const song = factory('song')
const putMock = this.mock(http, 'put')
queueStore.queue(song)
@ -33,7 +33,7 @@ new class extends UnitTestCase {
})
it('queues to top', () => {
const song = factory<Song>('song')
const song = factory('song')
const putMock = this.mock(http, 'put')
queueStore.queueToTop(song)
@ -43,7 +43,7 @@ new class extends UnitTestCase {
})
it('replaces the whole queue', () => {
const newSongs = factory<Song>('song', 2)
const newSongs = factory('song', 2)
const putMock = this.mock(http, 'put')
queueStore.replaceQueueWith(newSongs)
@ -101,7 +101,7 @@ new class extends UnitTestCase {
})
it('fetches random songs to queue', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const getMock = this.mock(http, 'get').mockResolvedValue(songs)
const syncMock = this.mock(songStore, 'syncWithVault', songs)
const putMock = this.mock(http, 'put')
@ -115,7 +115,7 @@ new class extends UnitTestCase {
})
it('fetches random songs to queue with a custom order', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const getMock = this.mock(http, 'get').mockResolvedValue(songs)
const syncMock = this.mock(songStore, 'syncWithVault', songs)
const putMock = this.mock(http, 'put')

View file

@ -7,7 +7,7 @@ import { recentlyPlayedStore, songStore } from '.'
new class extends UnitTestCase {
protected test () {
it('fetches the recently played songs', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const getMock = this.mock(http, 'get').mockResolvedValue(songs)
const syncMock = this.mock(songStore, 'syncWithVault', songs)
@ -20,17 +20,17 @@ new class extends UnitTestCase {
it('fetches when attempting to add a new song and the state is empty', async () => {
recentlyPlayedStore.state.playables = []
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const fetchMock = this.mock(recentlyPlayedStore, 'fetch').mockResolvedValue(songs)
await recentlyPlayedStore.add(factory<Song>('song'))
await recentlyPlayedStore.add(factory('song'))
expect(fetchMock).toHaveBeenCalled()
})
it('adds a song to the state', async () => {
const newSong = factory<Song>('song')
const songs = factory<Song>('song', 10)
const newSong = factory('song')
const songs = factory('song', 10)
const exceptSongs = songs.slice(0, 7)
// We don't want to keep the reference to the original songs
@ -44,7 +44,7 @@ new class extends UnitTestCase {
})
it('deduplicates when adding a song to the state', async () => {
const songs = factory<Song>('song', 10)
const songs = factory('song', 10)
const newSong = songs[1]
const exceptSongs = songs.slice(0, 7)

View file

@ -22,9 +22,9 @@ new class extends UnitTestCase {
protected test () {
it('performs an excerpt search', async () => {
const result: ExcerptSearchResult = {
playables: factory<Song>('song', 3),
albums: factory<Album>('album', 3),
artists: factory<Artist>('artist', 3)
playables: factory('song', 3),
albums: factory('album', 3),
artists: factory('artist', 3)
}
const getMock = this.mock(http, 'get').mockResolvedValue(result)
@ -45,7 +45,7 @@ new class extends UnitTestCase {
})
it('performs a song search', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const getMock = this.mock(http, 'get').mockResolvedValue(songs)
const syncMock = this.mock(songStore, 'syncWithVault', songs)
@ -59,7 +59,7 @@ new class extends UnitTestCase {
})
it('resets the song result state', () => {
searchStore.state.songs = factory<Song>('song', 3)
searchStore.state.songs = factory('song', 3)
searchStore.resetSongResultState()
expect(searchStore.state.songs).toEqual([])
})

View file

@ -25,42 +25,42 @@ new class extends UnitTestCase {
protected test () {
it('gets a song by ID', () => {
const song = reactive(factory<Song>('song', { id: 'foo' }))
const song = reactive(factory('song', { id: 'foo' }))
songStore.vault.set('foo', reactive(song))
songStore.vault.set('bar', reactive(factory<Song>('song', { id: 'bar' })))
songStore.vault.set('bar', reactive(factory('song', { id: 'bar' })))
expect(songStore.byId('foo')).toBe(song)
})
it('gets songs by IDs', () => {
const foo = reactive(factory<Song>('song', { id: 'foo' }))
const bar = reactive(factory<Song>('song', { id: 'bar' }))
const foo = reactive(factory('song', { id: 'foo' }))
const bar = reactive(factory('song', { id: 'bar' }))
songStore.vault.set('foo', foo)
songStore.vault.set('bar', bar)
songStore.vault.set('baz', reactive(factory<Song>('song', { id: 'baz' })))
songStore.vault.set('baz', reactive(factory('song', { id: 'baz' })))
expect(songStore.byIds(['foo', 'bar'])).toEqual([foo, bar])
})
it('gets formatted length', () => {
expect(songStore.getFormattedLength(factory<Song>('song', { length: 123 }))).toBe('2 min 3 sec')
expect(songStore.getFormattedLength(factory('song', { length: 123 }))).toBe('2 min 3 sec')
expect(songStore.getFormattedLength([
factory<Song>('song', { length: 122 }),
factory<Song>('song', { length: 123 })
factory('song', { length: 122 }),
factory('song', { length: 123 })
])).toBe('4 min 5 sec')
})
it('gets songs by album', () => {
const songs = reactive(factory<Song>('song', 2, { album_id: 3 }))
const songs = reactive(factory('song', 2, { album_id: 3 }))
songStore.vault.set(songs[0].id, songs[0])
songStore.vault.set(songs[1].id, songs[1])
const album = factory<Album>('album', { id: 3 })
const album = factory('album', { id: 3 })
expect(songStore.byAlbum(album)).toEqual(songs)
})
it('resolves a song', async () => {
const song = factory<Song>('song')
const song = factory('song')
const getMock = this.mock(http, 'get').mockResolvedValueOnce(song)
expect(await songStore.resolve(song.id)).toEqual(song)
@ -72,17 +72,17 @@ new class extends UnitTestCase {
})
it('matches a song', () => {
const song = factory<Song>('song', { title: 'An amazing song' })
const songs = [song, ...factory<Song>('song', 3)]
const song = factory('song', { title: 'An amazing song' })
const songs = [song, ...factory('song', 3)]
expect(songStore.match('An amazing song', songs)).toEqual(song)
expect(songStore.match('An Amazing Song', songs)).toEqual(song)
})
it('registers a play', async () => {
const song = factory<Song>('song', { play_count: 42 })
const song = factory('song', { play_count: 42 })
const postMock = this.mock(http, 'post').mockResolvedValueOnce(factory<Interaction>('interaction', {
const postMock = this.mock(http, 'post').mockResolvedValueOnce(factory('interaction', {
song_id: song.id,
play_count: 50
}))
@ -93,7 +93,7 @@ new class extends UnitTestCase {
})
it('scrobbles', async () => {
const song = factory<Song>('song')
const song = factory('song')
song.play_start_time = 123456789
const postMock = this.mock(http, 'post')
@ -103,12 +103,12 @@ new class extends UnitTestCase {
})
it('updates songs', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const result: SongUpdateResult = {
playables: factory<Song>('song', 3),
albums: factory<Album>('album', 2),
artists: factory<Artist>('artist', 2),
playables: factory('song', 3),
albums: factory('album', 2),
artists: factory('artist', 2),
removed: {
albums: [{
id: 10,
@ -155,7 +155,7 @@ new class extends UnitTestCase {
it('gets source URL', () => {
commonStore.state.cdn_url = 'http://test/'
const song = factory<Song>('song', { id: 'foo' })
const song = factory('song', { id: 'foo' })
this.mock(authService, 'getAudioToken', 'hadouken')
expect(songStore.getSourceUrl(song)).toBe('http://test/play/foo?t=hadouken')
@ -166,12 +166,12 @@ new class extends UnitTestCase {
})
it('gets shareable URL', () => {
const song = factory<Song>('song', { id: 'foo' })
const song = factory('song', { id: 'foo' })
expect(songStore.getShareableUrl(song)).toBe('http://test/#/song/foo')
})
it('syncs with the vault', () => {
const song = factory<Song>('song', {
const song = factory('song', {
playback_state: null
})
@ -190,7 +190,7 @@ new class extends UnitTestCase {
it('watches play count tracking', async () => {
const refreshMock = this.mock(overviewStore, 'refreshPlayStats')
const song = reactive(factory<Song>('song', {
const song = reactive(factory('song', {
album_id: 10,
artist_id: 42,
album_artist_id: 43,
@ -206,8 +206,8 @@ new class extends UnitTestCase {
})
it('fetches for album', async () => {
const songs = factory<Song>('song', 3)
const album = factory<Album>('album', { id: 42 })
const songs = factory('song', 3)
const album = factory('album', { id: 42 })
const getMock = this.mock(http, 'get').mockResolvedValueOnce(songs)
const syncMock = this.mock(songStore, 'syncWithVault', songs)
@ -218,8 +218,8 @@ new class extends UnitTestCase {
})
it('fetches for artist', async () => {
const songs = factory<Song>('song', 3)
const artist = factory<Artist>('artist', { id: 42 })
const songs = factory('song', 3)
const artist = factory('artist', { id: 42 })
const getMock = this.mock(http, 'get').mockResolvedValueOnce(songs)
const syncMock = this.mock(songStore, 'syncWithVault', songs)
@ -230,8 +230,8 @@ new class extends UnitTestCase {
})
it('fetches for playlist', async () => {
const songs = factory<Song>('song', 3)
const playlist = factory<Playlist>('playlist', { id: '966268ea-935d-4f63-a84e-180385376a78' })
const songs = factory('song', 3)
const playlist = factory('playlist', { id: '966268ea-935d-4f63-a84e-180385376a78' })
this.mock(playlistStore, 'byId').mockReturnValueOnce(playlist)
const getMock = this.mock(http, 'get').mockResolvedValueOnce(songs)
const syncMock = this.mock(songStore, 'syncWithVault', songs)
@ -245,8 +245,8 @@ new class extends UnitTestCase {
})
it('fetches for playlist with cache', async () => {
const songs = factory<Song>('song', 3)
const playlist = factory<Playlist>('playlist', { id: '966268ea-935d-4f63-a84e-180385376a78' })
const songs = factory('song', 3)
const playlist = factory('playlist', { id: '966268ea-935d-4f63-a84e-180385376a78' })
this.mock(playlistStore, 'byId').mockReturnValueOnce(playlist)
cache.set(['playlist.songs', playlist.id], songs)
@ -260,8 +260,8 @@ new class extends UnitTestCase {
})
it('fetches for playlist discarding cache', async () => {
const songs = factory<Song>('song', 3)
const playlist = factory<Playlist>('playlist', { id: '966268ea-935d-4f63-a84e-180385376a78' })
const songs = factory('song', 3)
const playlist = factory('playlist', { id: '966268ea-935d-4f63-a84e-180385376a78' })
this.mock(playlistStore, 'byId').mockReturnValueOnce(playlist)
cache.set(['playlist.songs', playlist.id], songs)
@ -275,7 +275,7 @@ new class extends UnitTestCase {
})
it('paginates', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const getMock = this.mock(http, 'get').mockResolvedValueOnce({
data: songs,
@ -302,7 +302,7 @@ new class extends UnitTestCase {
})
it('paginates for genre', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const reactiveSongs = reactive(songs)
const getMock = this.mock(http, 'get').mockResolvedValueOnce({
@ -331,7 +331,7 @@ new class extends UnitTestCase {
})
it('fetches random songs for genre', async () => {
const songs = factory<Song>('song', 3)
const songs = factory('song', 3)
const reactiveSongs = reactive(songs)
const getMock = this.mock(http, 'get').mockResolvedValueOnce(songs)

View file

@ -4,7 +4,7 @@ import factory from '@/__tests__/factory'
import { http } from '@/services'
import { CreateUserData, UpdateUserData, userStore } from '.'
const currentUser = factory<User>('user', {
const currentUser = factory('user', {
id: 1,
name: 'John Doe',
email: 'john@doe.com',
@ -26,7 +26,7 @@ new class extends UnitTestCase {
})
it('syncs with vault', () => {
const user = factory<User>('user')
const user = factory('user')
expect(userStore.syncWithVault(user)).toEqual([user])
expect(userStore.vault.size).toBe(2)
@ -34,7 +34,7 @@ new class extends UnitTestCase {
})
it('fetches users', async () => {
const users = factory<User>('user', 3)
const users = factory('user', 3)
const getMock = this.mock(http, 'get').mockResolvedValue(users)
await userStore.fetch()
@ -44,7 +44,7 @@ new class extends UnitTestCase {
})
it('gets user by id', () => {
const user = factory<User>('user', { id: 2 })
const user = factory('user', { id: 2 })
userStore.syncWithVault(user)
expect(userStore.byId(2)).toEqual(user)
@ -58,7 +58,7 @@ new class extends UnitTestCase {
email: 'jane@doe.com'
}
const user = factory<User>('user', data)
const user = factory('user', data)
const postMock = this.mock(http, 'post').mockResolvedValue(user)
expect(await userStore.store(data)).toEqual(user)
@ -68,7 +68,7 @@ new class extends UnitTestCase {
})
it('updates a user', async () => {
const user = factory<User>('user', { id: 2 })
const user = factory('user', { id: 2 })
userStore.state.users.push(...userStore.syncWithVault(user))
const data: UpdateUserData = {
@ -90,7 +90,7 @@ new class extends UnitTestCase {
it('deletes a user', async () => {
const deleteMock = this.mock(http, 'delete')
const user = factory<User>('user', { id: 2 })
const user = factory('user', { id: 2 })
userStore.state.users.push(...userStore.syncWithVault(user))
expect(userStore.vault.has(2)).toBe(true)

View file

@ -154,7 +154,6 @@ interface Playable {
play_count_registered?: boolean
play_count: number
play_start_time?: number
genre: string
preloaded?: boolean
playback_state?: PlaybackState
liked: boolean
@ -172,6 +171,7 @@ interface Song extends Playable {
artist_name: Artist['name']
album_artist_id: Artist['id']
album_artist_name: Artist['name']
genre: string
track: number | null
disc: number | null
year: number | null