feat(test): add several service tests

This commit is contained in:
Phan An 2022-05-13 19:58:38 +02:00
parent 4efd462974
commit cc36f49796
No known key found for this signature in database
GPG key ID: A81E4477F0BB6FDC
63 changed files with 236 additions and 298 deletions

View file

@ -9,7 +9,7 @@ import factory from '@/__tests__/factory'
declare type Methods<T> = { [K in keyof T]: T[K] extends Closure ? K : never; }[keyof T] & (string | symbol);
export default abstract class ComponentTestCase {
export default abstract class UnitTestCase {
private backupMethods = new Map()
public constructor () {

View file

@ -1,13 +1,13 @@
/* eslint @typescript-eslint/no-unused-vars: 0 */
import _, { Cancelable } from 'lodash'
import _ from 'lodash'
_.orderBy = jest.fn(<T>(collection: T[]): T[] => collection)
_.orderBy = jest.fn(<T> (collection: T[]): T[] => collection)
_.shuffle = jest.fn(<T>(collection: T[]): T[] => collection)
_.shuffle = jest.fn(<T> (collection: T[]): T[] => collection)
_.throttle = jest.fn((fn: Function, wait: number): any => fn)
_.sample = jest.fn(<T>(collection: T[]): T | undefined => {
_.sample = jest.fn(<T> (collection: T[]): T | undefined => {
return collection.length ? collection[0] : undefined
})

View file

@ -1,9 +0,0 @@
module.exports = {
process () {
return 'module.exports = {};'
},
getCacheKey () {
return 'imageTransform'
}
}

View file

@ -1,63 +0,0 @@
import Component from '@/components/utils/event-listeners.vue'
import factory from '@/__tests__/factory'
import { playlistStore, userStore } from '@/stores'
import router from '@/router'
import { authService } from '@/services'
import { alerts, eventBus } from '@/utils'
import { mock } from '@/__tests__/__helpers__'
import { mount } from '@/__tests__/adapter'
describe('utils/event-listeners', () => {
afterEach(() => {
jest.resetModules()
jest.clearAllMocks()
})
it('confirms a playlist deleting if the playlist is not empty', () => {
mount(Component)
const confirmMock = mock(alerts, 'confirm')
eventBus.emit('PLAYLIST_DELETE', factory('playlist', {
name: 'Foo',
populated: true,
songs: factory('song', 3)
}))
expect(confirmMock).toHaveBeenCalledWith(`Delete the playlist "Foo"?`, expect.any(Function))
})
it("doesn't confirm deleting a playlist if the playlist is empty", () => {
const playlist = factory('playlist', {
populated: true,
songs: []
})
mount(Component)
const confirmMock = mock(alerts, 'confirm')
const deleteMock = mock(playlistStore, 'delete')
eventBus.emit('PLAYLIST_DELETE', playlist)
expect(confirmMock).not.toHaveBeenCalled()
expect(deleteMock).toHaveBeenCalledWith(playlist)
})
it('listens to log out event', () => {
const wrapper = mount(Component)
const authDestroyMock = mock(authService, 'destroy')
const logOutMock = mock(userStore, 'logout')
eventBus.emit('LOG_OUT')
wrapper.vm.$nextTick(() => {
expect(authDestroyMock).toHaveBeenCalled()
expect(logOutMock).toHaveBeenCalled()
})
})
it('listen to koel-ready event', () => {
mount(Component)
const initRouterMock = mock(router, 'init')
eventBus.emit('KOEL_READY')
expect(initRouterMock).toHaveBeenCalled()
})
})

View file

@ -1,56 +0,0 @@
import { downloadService } from '@/services'
import { favoriteStore } from '@/stores'
import factory from '@/__tests__/factory'
import { mock } from '@/__tests__/__helpers__'
describe('services/download', () => {
afterEach(() => {
jest.resetModules()
jest.restoreAllMocks()
jest.clearAllMocks()
})
it('downloads songs', () => {
const triggerMock = mock(downloadService, 'trigger')
downloadService.fromSongs([factory<Song>('song', { id: 'foo' }), factory<Song>('song', { id: 'bar' })])
expect(triggerMock).toHaveBeenCalledWith('songs?songs[]=bar&songs[]=foo&')
})
it('downloads all by artist', () => {
const triggerMock = mock(downloadService, 'trigger')
downloadService.fromArtist(factory<Artist>('artist', { id: 42 }))
expect(triggerMock).toHaveBeenCalledWith('artist/42')
})
it('downloads all in album', () => {
const triggerMock = mock(downloadService, 'trigger')
downloadService.fromAlbum(factory<Album>('album', { id: 42 }))
expect(triggerMock).toHaveBeenCalledWith('album/42')
})
it.each<[Song[], boolean]>([[[], false], [factory<Song>('song', 5), true]])(
'downloads playlist if available',
(songs, triggered) => {
const triggerMock = mock(downloadService, 'trigger')
downloadService.fromPlaylist(factory<Playlist>('playlist', { id: 42, songs }))
triggered
? expect(triggerMock).toHaveBeenCalledWith('playlist/42')
: expect(triggerMock).not.toHaveBeenCalled()
})
it.each<[Song[], boolean]>([[[], false], [factory<Song>('song', 5), true]])(
'downloads favorites if available',
(songs, triggered) => {
const triggerMock = mock(downloadService, 'trigger')
favoriteStore.all = songs
downloadService.fromFavorites()
triggered
? expect(triggerMock).toHaveBeenCalledWith('favorites')
: expect(triggerMock).not.toHaveBeenCalled()
})
})

View file

@ -1,26 +0,0 @@
import { get, set, remove } from 'local-storage'
import { localStorageService } from '@/services'
describe('services/ls', () => {
it('gets an existing item from local storage', () => {
set('foo', 'bar')
expect(localStorageService.get('foo')).toBe('bar')
})
it('returns the default value for a non exising item', () => {
remove('foo')
expect(localStorageService.get('foo', 42)).toBe(42)
})
it('sets an item into local storage', () => {
remove('foo')
localStorageService.set('foo', 42)
expect(get('foo')).toBe(42)
})
it('correctly removes an item from local storage', () => {
set('foo', 42)
localStorageService.remove('foo')
expect(get('foo')).toBeNull()
})
})

View file

@ -1,30 +0,0 @@
import { youtubeService } from '@/services'
import { eventBus } from '@/utils'
import router from '@/router'
import factory from '@/__tests__/factory'
import { mock } from '@/__tests__/__helpers__'
describe('services/youtube', () => {
afterEach(() => {
jest.resetModules()
jest.restoreAllMocks()
jest.clearAllMocks()
})
it('plays a video', () => {
const video = factory<YouTubeVideo>('video', {
id: {
videoId: 'foo'
},
snippet: {
title: 'Bar'
}
})
const emitMock = mock(eventBus, 'emit')
const goMock = mock(router, 'go')
youtubeService.play(video)
expect(emitMock).toHaveBeenCalledWith('PLAY_YOUTUBE_VIDEO', { id: 'foo', title: 'Bar' })
expect(goMock).toHaveBeenCalledWith('youtube')
})
})

View file

@ -2,12 +2,12 @@ import { fireEvent } from '@testing-library/vue'
import { expect, it } from 'vitest'
import { downloadService, playbackService } from '@/services'
import factory from '@/__tests__/factory'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import AlbumCard from './AlbumCard.vue'
let album: Album
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected beforeEach () {
super.beforeEach(() => {
album = factory<Album>('album', {

View file

@ -1,11 +1,11 @@
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import factory from '@/__tests__/factory'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import AlbumInfo from './AlbumInfo.vue'
import AlbumThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it.each([['sidebar'], ['full']])('renders in %s mode', async (mode: string) => {
const { getByTestId } = this.render(AlbumInfo, {

View file

@ -1,10 +1,10 @@
import factory from '@/__tests__/factory'
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import AlbumTrackList from './AlbumTrackList.vue'
import TrackListItem from './AlbumTrackListItem.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('lists the correct number of tracks', () => {
const { queryAllByTestId } = this.render(AlbumTrackList, {

View file

@ -3,7 +3,7 @@ import { expect, it } from 'vitest'
import factory from '@/__tests__/factory'
import { queueStore, songStore } from '@/stores'
import { playbackService } from '@/services'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import AlbumTrackListItem from './AlbumTrackListItem.vue'
let song: Song
@ -15,7 +15,7 @@ const track = {
const album = factory<Album>('album', { id: 42 })
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected beforeEach () {
super.beforeEach(() => (song = factory<Song>('song')))
}

View file

@ -2,12 +2,12 @@ import { fireEvent } from '@testing-library/vue'
import { expect, it } from 'vitest'
import factory from '@/__tests__/factory'
import { downloadService, playbackService } from '@/services'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import ArtistCard from './ArtistCard.vue'
let artist: Artist
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected beforeEach () {
super.beforeEach(() => {
artist = factory<Artist>('artist', {

View file

@ -1,11 +1,11 @@
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import factory from '@/__tests__/factory'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import ArtistInfo from './ArtistInfo.vue'
import ArtistThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it.each([['sidebar'], ['full']])('renders in %s mode', async (mode: string) => {
const { getByTestId } = this.render(ArtistInfo, {

View file

@ -1,11 +1,11 @@
import { fireEvent } from '@testing-library/vue'
import { expect, it } from 'vitest'
import { userStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import LoginFrom from './LoginForm.vue'
import Btn from '@/components/ui/Btn.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders', () => expect(this.render(LoginFrom, {
global: {

View file

@ -4,11 +4,11 @@ import { fireEvent, queryAllByTestId } from '@testing-library/vue'
import { eventBus } from '@/utils'
import factory from '@/__tests__/factory'
import compareVersions from 'compare-versions'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import AppHeader from './AppHeader.vue'
import SearchForm from '@/components/ui/SearchForm.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('toggles sidebar (mobile only)', async () => {
isMobile.any = true

View file

@ -3,10 +3,10 @@ import { httpService } from '@/services'
import { eventBus } from '@/utils'
import { it } from 'vitest'
import { EventName } from '@/config'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import ModalWrapper from './ModalWrapper.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it.each<[string, EventName, User | Song | any]>([
['add-user-form', 'MODAL_SHOW_ADD_USER_FORM', undefined],

View file

@ -6,10 +6,10 @@ import Volume from '@/components/ui/Volume.vue'
import LikeButton from '@/components/song/SongLikeButton.vue'
import RepeatModeSwitch from '@/components/ui/RepeatModeSwitch.vue'
import Equalizer from '@/components/ui/Equalizer.vue'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import FooterExtraControls from './FooterExtraControls.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders', () => {
preferenceStore.state.showExtraPanel = true

View file

@ -1,9 +1,9 @@
import { expect, it } from 'vitest'
import factory from '@/__tests__/factory'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import FooterMiddlePane from './FooterMiddlePane.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders without a song', () => {
expect(this.render(FooterMiddlePane).html()).toMatchSnapshot()

View file

@ -2,10 +2,10 @@ import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import { playbackService } from '@/services'
import factory from '@/__tests__/factory'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import FooterPlayerControls from './FooterPlayerControls.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it.each<[string, string, MethodOf<typeof playbackService>]>([
['plays next song', 'Play next song', 'playNext'],

View file

@ -4,10 +4,10 @@ import factory from '@/__tests__/factory'
import { commonStore } from '@/stores'
import { songInfoService } from '@/services'
import { eventBus } from '@/utils'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import ExtraPanel from './ExtraPanel.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent () {
return this.render(ExtraPanel, {
props: {

View file

@ -2,12 +2,12 @@ import { expect, it } from 'vitest'
import factory from '@/__tests__/factory'
import { eventBus } from '@/utils'
import { albumStore, preferenceStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import MainContent from '@/components/layout/main-wrapper/MainContent.vue'
import AlbumArtOverlay from '@/components/ui/AlbumArtOverlay.vue'
import Visualizer from '@/components/ui/Visualizer.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('has a translucent overlay per album', async () => {
this.mock(albumStore, 'getThumbnail', 'https://foo/bar.jpg')

View file

@ -1,7 +1,7 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('has already been tested in the integration suite', () => expect('😄').toBeTruthy())
}

View file

@ -1,10 +1,10 @@
import { expect, it } from 'vitest'
import { commonStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import AboutKoelModel from './AboutKoelModal.vue'
import Btn from '@/components/ui/Btn.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected beforeEach () {
super.beforeEach(() => (KOEL_ENV = ''));
}

View file

@ -2,10 +2,10 @@ import { expect, it, vi } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import { eventBus } from '@/utils'
import { preferenceStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import SupportKoel from './SupportKoel.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected beforeEach () {
super.beforeEach(() => vi.useFakeTimers());
}

View file

@ -3,9 +3,9 @@ import PlaylistNameEditor from '@/components/playlist/PlaylistNameEditor.vue'
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import { playlistStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
new class extends ComponentTestCase {
new class extends UnitTestCase {
private useEditor () {
const updateMock = this.mock(playlistStore, 'update')

View file

@ -1,10 +1,10 @@
import factory from '@/__tests__/factory'
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import PlaylistSidebarItem from '@/components/playlist/PlaylistSidebarItem.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
renderComponent (playlist: Record<string, any>, type: PlaylistType = 'playlist') {
return this.render(PlaylistSidebarItem, {
props: {

View file

@ -3,9 +3,9 @@ import { playlistStore } from '@/stores'
import factory from '@/__tests__/factory'
import PlaylistSidebarList from './PlaylistSidebarList.vue'
import PlaylistSidebarItem from './PlaylistSidebarItem.vue'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders all playlists', () => {
playlistStore.state.playlists = [

View file

@ -1,7 +1,7 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('is already covered by E2E', () => expect('🤞').toBeTruthy())
}

View file

@ -1,9 +1,9 @@
import { expect, it } from 'vitest'
import isMobile from 'ismobilejs'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import PreferencesForm from './PreferencesForm.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('has "Transcode on mobile" option for mobile users', () => {
isMobile.phone = true

View file

@ -1,4 +1,4 @@
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import ThemeCard from './ThemeCard.vue'
@ -8,7 +8,7 @@ const theme: Theme = {
thumbnailColor: '#f00'
}
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent () {
return this.render(ThemeCard, {
props: {

View file

@ -1,9 +1,9 @@
import { expect, it } from 'vitest'
import { themeStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import ThemeList from './ThemeList.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('displays all themes', () => {
expect(this.render(ThemeList).getAllByTestId('theme-card').length).toEqual(themeStore.state.themes.length)

View file

@ -1,10 +1,10 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { searchStore } from '@/stores'
import { eventBus } from '@/utils'
import SearchExceptsScreen from './SearchExcerptsScreen.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('executes searching when the search keyword is changed', async () => {
const mock = this.mock(searchStore, 'excerptSearch')

View file

@ -1,9 +1,9 @@
import { expect, it } from 'vitest'
import { searchStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import SearchSongResultsScreen from './SearchSongResultsScreen.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('searches for prop query on created', () => {
const resetResultMock = this.mock(searchStore, 'resetSongResultState')

View file

@ -2,7 +2,7 @@ import { clone } from 'lodash'
import { expect, it } from 'vitest'
import factory from '@/__tests__/factory'
import { favoriteStore, playlistStore, queueStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import Btn from '@/components/ui/Btn.vue'
import AddToMenu from './AddToMenu.vue'
import { arrayify } from '@/utils'
@ -17,7 +17,7 @@ const config: AddToMenuConfig = {
newPlaylist: true
}
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent (customConfig: Partial<AddToMenuConfig> = {}) {
songs = factory<Song>('song', 5)

View file

@ -3,12 +3,12 @@ import { queueStore } from '@/stores'
import { playbackService } from '@/services'
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import SongCard from './SongCard.vue'
let song: Song
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent (playbackState: PlaybackState = 'Stopped') {
song = factory<Song>('song', {
playbackState,

View file

@ -2,10 +2,10 @@ import { expect, it } from 'vitest'
import factory from '@/__tests__/factory'
import { fireEvent } from '@testing-library/vue'
import { favoriteStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import SongLikeButton from './SongLikeButton.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it.each<[boolean, string]>([
[true, 'btn-like-liked'],

View file

@ -3,12 +3,12 @@ import factory from '@/__tests__/factory'
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import { eventBus, noop } from '@/utils'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import SongList from './SongList.vue'
let songs: Song[]
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected beforeEach () {
// suppress the warning
super.beforeEach(() => eventBus.on('SET_SELECTED_SONGS', noop))

View file

@ -2,13 +2,13 @@ import { take } from 'lodash'
import { expect, it } from 'vitest'
import factory from '@/__tests__/factory'
import { fireEvent } from '@testing-library/vue'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import SongListControls from './SongListControls.vue'
import AddToMenu from '@/components/song/AddToMenu.vue'
import Btn from '@/components/ui/Btn.vue'
import BtnGroup from '@/components/ui/BtnGroup.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent (selectedSongCount = 1, config: Partial<SongListControlsConfig> = {}) {
const songs = factory<Song>('song', 5)

View file

@ -5,11 +5,11 @@ import { queueStore } from '@/stores'
import { playbackService } from '@/services'
import { fireEvent } from '@testing-library/vue'
import SongListItem from './SongListItem.vue'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
let row: SongRow
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent (columns: SongListColumn[] = ['track', 'title', 'artist', 'album', 'length']) {
row = {
song: factory<Song>('song'),

View file

@ -1,12 +1,12 @@
import { expect, it } from 'vitest'
import { albumStore } from '@/stores'
import factory from '@/__tests__/factory'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import AlbumArtOverlay from './AlbumArtOverlay.vue'
let album: Album
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent () {
album = factory<Album>('album')

View file

@ -1,5 +1,5 @@
import { orderBy } from 'lodash'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import { playbackService } from '@/services'
@ -10,7 +10,7 @@ import Thumbnail from './AlbumArtistThumbnail.vue'
let album: Album
let artist: Artist
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderForAlbum () {
album = factory<Album>('album', {
name: 'IV',

View file

@ -1,8 +1,8 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import AppleMusicButton from './AppleMusicButton.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders', () => {
expect(this.render(AppleMusicButton, {

View file

@ -1,8 +1,8 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import Btn from './Btn.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders', () => {
expect(this.render(Btn, {

View file

@ -1,9 +1,9 @@
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import BtnCloseModal from './BtnCloseModal.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders', () => expect(this.render(BtnCloseModal).html()).toMatchSnapshot())

View file

@ -1,9 +1,9 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import BtnGroup from './BtnGroup.vue'
import Btn from './Btn.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderButtonToSlot (text: string) {
return this.render(Btn, {
slots: {

View file

@ -1,10 +1,10 @@
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import { $ } from '@/utils'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import BtnScrollToTop from './BtnScrollToTop.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders', () => {
expect(this.render(BtnScrollToTop).html()).toMatchSnapshot()

View file

@ -1,12 +1,12 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import factory from '@/__tests__/factory'
import { eventBus } from '@/utils'
import { fireEvent } from '@testing-library/vue'
import LyricsPane from './LyricsPane.vue'
import TextMagnifier from '@/components/ui/TextMagnifier.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent (song?: Song) {
song = song || factory<Song>('song', {
lyrics: 'Foo bar baz qux'

View file

@ -1,11 +1,11 @@
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { expect, it } from 'vitest'
import { OverlayState } from 'koel/types/ui'
import { eventBus } from '@/utils'
import Overlay from './Overlay.vue'
import SoundBar from '@/components/ui/SoundBar.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
private async showOverlay (type: OverlayState['type'] = 'loading') {
const rendered = this.render(Overlay, {
global: {

View file

@ -1,11 +1,11 @@
import { expect, it } from 'vitest'
import { preferenceStore } from '@/stores'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import RepeatModeSwitch from './RepeatModeSwitch.vue'
import { fireEvent } from '@testing-library/vue'
import { playbackService } from '@/services'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('changes mode', async () => {
const mock = this.mock(playbackService, 'changeRepeatMode')

View file

@ -1,10 +1,10 @@
import isMobile from 'ismobilejs'
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import ScreenControlsToggler from './ScreenControlsToggler.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders and emits an event on mobile', async () => {
isMobile.phone = true

View file

@ -1,8 +1,8 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import ScreenEmptyState from './ScreenEmptyState.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders', () => {
expect(this.render(ScreenEmptyState, {

View file

@ -1,8 +1,8 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import ScreenHeader from './ScreenHeader.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('renders', () => {
expect(this.render(ScreenHeader, {

View file

@ -1,11 +1,11 @@
import { expect, it, vi } from 'vitest'
import router from '@/router'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import SearchForm from './SearchForm.vue'
import { fireEvent } from '@testing-library/vue'
import { eventBus } from '@/utils'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
// skipping because of unstable getRootNode() issues
it.skip('sets focus into search box when requested', async () => {

View file

@ -1,8 +1,8 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import ViewModeSwitch from './ViewModeSwitch.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it.each<[ArtistAlbumViewMode]>([['thumbnails'], ['list']])('renders %s mode', mode => {
expect(this.render(ViewModeSwitch, {

View file

@ -1,10 +1,10 @@
import { expect, it } from 'vitest'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { fireEvent } from '@testing-library/vue'
import { playbackService, socketService } from '@/services'
import Volume from './Volume.vue'
new class extends ComponentTestCase {
new class extends UnitTestCase {
protected test () {
it('mutes and unmutes', async () => {
const muteMock = this.mock(playbackService, 'mute')

View file

@ -1,12 +1,12 @@
import { expect, it } from 'vitest'
import { fireEvent } from '@testing-library/vue'
import { youTubeService } from '@/services'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import YouTubeVideoItem from './YouTubeVideoItem.vue'
let video: YouTubeVideo
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent () {
video = {
id: {

View file

@ -1,6 +1,6 @@
import { expect, it } from 'vitest'
import factory from '@/__tests__/factory'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import YouTubeVideoList from './YouTubeVideoList.vue'
import Btn from '@/components/ui/Btn.vue'
import YouTubeVideo from '@/components/ui/YouTubeVideoItem.vue'
@ -9,7 +9,7 @@ import { fireEvent } from '@testing-library/vue'
let song: Song
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent () {
song = factory<Song>('song', {
youtube: {

View file

@ -1,6 +1,6 @@
import { expect, it } from 'vitest'
import { UploadFile, UploadStatus } from '@/config'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { fireEvent } from '@testing-library/vue'
import { uploadService } from '@/services'
import Btn from '@/components/ui/Btn.vue'
@ -8,7 +8,7 @@ import UploadItem from './UploadItem.vue'
let file: UploadFile
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent (status: UploadStatus) {
file = {
status,

View file

@ -1,12 +1,12 @@
import { expect, it } from 'vitest'
import factory from '@/__tests__/factory'
import ComponentTestCase from '@/__tests__/ComponentTestCase'
import UnitTestCase from '@/__tests__/UnitTestCase'
import UserCard from './UserCard.vue'
import Btn from '@/components/ui/Btn.vue'
import { fireEvent } from '@testing-library/vue'
import router from '@/router'
new class extends ComponentTestCase {
new class extends UnitTestCase {
private renderComponent (user: User) {
return this.render(UserCard, {
props: {

View file

@ -0,0 +1,63 @@
import { favoriteStore, playlistStore } from '@/stores'
import factory from '@/__tests__/factory'
import { expect, it } from 'vitest'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { downloadService } from './downloadService'
new class extends UnitTestCase {
protected test () {
it('downloads songs', () => {
const mock = this.mock(downloadService, 'trigger')
downloadService.fromSongs([factory<Song>('song', { id: 'foo' }), factory<Song>('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 }))
expect(mock).toHaveBeenCalledWith('artist/42')
})
it('downloads all in album', () => {
const mock = this.mock(downloadService, 'trigger')
downloadService.fromAlbum(factory<Album>('album', { id: 42 }))
expect(mock).toHaveBeenCalledWith('album/42')
})
it('downloads a playlist', () => {
const getSongsMock = this.mock(playlistStore, 'getSongs', factory<Song>('song', 5))
const mock = this.mock(downloadService, 'trigger')
const playlist = factory<Playlist>('playlist', { id: 42 })
downloadService.fromPlaylist(playlist)
expect(getSongsMock).toHaveBeenCalledWith(playlist)
expect(mock).toHaveBeenCalledWith('playlist/42')
})
it('does not download an empty playlist', () => {
const getSongsMock = this.mock(playlistStore, 'getSongs', [])
const triggerMock = this.mock(downloadService, 'trigger')
const playlist = factory<Playlist>('playlist')
downloadService.fromPlaylist(playlist)
expect(getSongsMock).toHaveBeenCalledWith(playlist)
expect(triggerMock).not.toHaveBeenCalled()
})
it.each<[Song[], boolean]>([[[], false], [factory<Song>('song', 5), true]])(
'downloads favorites if available',
(songs, triggered) => {
const mock = this.mock(downloadService, 'trigger')
favoriteStore.all = songs
downloadService.fromFavorites()
triggered ? expect(mock).toHaveBeenCalledWith('favorites') : expect(mock).not.toHaveBeenCalled()
})
}
}

View file

@ -3,26 +3,26 @@ import { authService } from '.'
import { arrayify } from '@/utils'
export const downloadService = {
fromSongs (songs: Song | Song[]): void {
fromSongs (songs: Song | Song[]) {
const query = arrayify(songs).reduce((q, song) => `songs[]=${song.id}&${q}`, '')
this.trigger(`songs?${query}`)
},
fromAlbum (album: Album): void {
fromAlbum (album: Album) {
this.trigger(`album/${album.id}`)
},
fromArtist (artist: Artist): void {
fromArtist (artist: Artist) {
this.trigger(`artist/${artist.id}`)
},
fromPlaylist (playlist: Playlist): void {
fromPlaylist (playlist: Playlist) {
if (playlistStore.getSongs(playlist).length) {
this.trigger(`playlist/${playlist.id}`)
}
},
fromFavorites (): void {
fromFavorites () {
if (favoriteStore.all.length) {
this.trigger('favorites')
}

View file

@ -0,0 +1,30 @@
import { get, remove, set } from 'local-storage'
import { expect, it } from 'vitest'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { localStorageService } from './localStorageService'
new class extends UnitTestCase {
protected test () {
it('gets an existing item from local storage', () => {
set('foo', 'bar')
expect(localStorageService.get('foo')).toBe('bar')
})
it('returns the default value for a non exising item', () => {
remove('foo')
expect(localStorageService.get('foo', 42)).toBe(42)
})
it('sets an item into local storage', () => {
remove('foo')
localStorageService.set('foo', 42)
expect(get('foo')).toBe(42)
})
it('correctly removes an item from local storage', () => {
set('foo', 42)
localStorageService.remove('foo')
expect(get('foo')).toBeNull()
})
}
}

View file

@ -0,0 +1,29 @@
import { eventBus } from '@/utils'
import router from '@/router'
import factory from '@/__tests__/factory'
import { expect, it } from 'vitest'
import UnitTestCase from '@/__tests__/UnitTestCase'
import { youTubeService } from './youTubeService'
new class extends UnitTestCase {
protected test () {
it('plays a video', () => {
const video = factory<YouTubeVideo>('video', {
id: {
videoId: 'foo'
},
snippet: {
title: 'Bar'
}
})
const emitMock = this.mock(eventBus, 'emit')
const goMock = this.mock(router, 'go')
youTubeService.play(video)
expect(emitMock).toHaveBeenCalledWith('PLAY_YOUTUBE_VIDEO', { id: 'foo', title: 'Bar' })
expect(goMock).toHaveBeenCalledWith('youtube')
})
}
}