mirror of
https://github.com/koel/koel
synced 2024-12-01 00:09:17 +00:00
feat(test): add ExtraPanel component tests
This commit is contained in:
parent
e51d8de337
commit
c85564bf0a
7 changed files with 93 additions and 134 deletions
|
@ -1,61 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`components/layout/ExtraPanel does not have a YouTube tab if not using YouTube 1`] = `
|
|
||||||
<section id="extra" data-testid="extra-panel" class="text-secondary showing">
|
|
||||||
<div class="tabs">
|
|
||||||
<div role="tablist" class="clear"><button aria-selected="true" aria-controls="extraPanelLyrics" id="extraTabLyrics" role="tab">
|
|
||||||
Lyrics
|
|
||||||
</button> <button aria-controls="extraPanelArtist" id="extraTabArtist" role="tab">
|
|
||||||
Artist
|
|
||||||
</button> <button aria-controls="extraPanelAlbum" id="extraTabAlbum" role="tab">
|
|
||||||
Album
|
|
||||||
</button>
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
<div class="panes">
|
|
||||||
<div aria-labelledby="extraTabLyrics" id="extraPanelLyrics" role="tabpanel" tabindex="0">
|
|
||||||
<lyricspane-stub></lyricspane-stub>
|
|
||||||
</div>
|
|
||||||
<div aria-labelledby="extraTabArtist" id="extraPanelArtist" role="tabpanel" tabindex="0" style="display: none;">
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
<div aria-labelledby="extraTabAlbum" id="extraPanelAlbum" role="tabpanel" tabindex="0" style="display: none;">
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
<div aria-labelledby="extraTabYouTube" id="extraPanelYouTube" role="tabpanel" tabindex="0" style="display: none;">
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`components/layout/ExtraPanel renders properly 1`] = `
|
|
||||||
<section id="extra" data-testid="extra-panel" class="text-secondary showing">
|
|
||||||
<div class="tabs">
|
|
||||||
<div role="tablist" class="clear"><button aria-selected="true" aria-controls="extraPanelLyrics" id="extraTabLyrics" role="tab">
|
|
||||||
Lyrics
|
|
||||||
</button> <button aria-controls="extraPanelArtist" id="extraTabArtist" role="tab">
|
|
||||||
Artist
|
|
||||||
</button> <button aria-controls="extraPanelAlbum" id="extraTabAlbum" role="tab">
|
|
||||||
Album
|
|
||||||
</button>
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
<div class="panes">
|
|
||||||
<div aria-labelledby="extraTabLyrics" id="extraPanelLyrics" role="tabpanel" tabindex="0">
|
|
||||||
<lyrics-pane-stub></lyrics-pane-stub>
|
|
||||||
</div>
|
|
||||||
<div aria-labelledby="extraTabArtist" id="extraPanelArtist" role="tabpanel" tabindex="0" style="display: none;">
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
<div aria-labelledby="extraTabAlbum" id="extraPanelAlbum" role="tabpanel" tabindex="0" style="display: none;">
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
<div aria-labelledby="extraTabYouTube" id="extraPanelYouTube" role="tabpanel" tabindex="0" style="display: none;">
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
`;
|
|
|
@ -1,54 +0,0 @@
|
||||||
import Component from '@/components/layout/main-wrapper/ExtraPanel.vue'
|
|
||||||
import factory from '@/__tests__/factory'
|
|
||||||
import { eventBus } from '@/utils'
|
|
||||||
import { songInfo } from '@/services'
|
|
||||||
import { mock } from '@/__tests__/__helpers__'
|
|
||||||
import { shallow, Wrapper } from '@/__tests__/adapter'
|
|
||||||
|
|
||||||
const shallowComponent = (data: Record<string, any> = {}): Wrapper => shallow(Component, {
|
|
||||||
stubs: ['lyrics-pane', 'artist-info', 'album-info', 'you-tube-video-list'],
|
|
||||||
data: () => data
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('components/layout/ExtraPanel', () => {
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetModules()
|
|
||||||
jest.clearAllMocks()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('renders properly', () => {
|
|
||||||
expect(shallowComponent()).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not have a YouTube tab if not using YouTube', async () => {
|
|
||||||
const wrapper = shallowComponent({
|
|
||||||
sharedState: {
|
|
||||||
useYouTube: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
expect(shallow(Component)).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a YouTube tab if using YouTube', async () => {
|
|
||||||
const wrapper = shallowComponent({
|
|
||||||
sharedState: {
|
|
||||||
useYouTube: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
expect(wrapper.has('#extraTabYouTube')).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it.each<[string]>([['#extraTabLyrics'], ['#extraTabAlbum'], ['#extraTabArtist']])('switches to "%s" tab', selector => {
|
|
||||||
expect(shallowComponent().click(selector).find('[aria-selected=true]').is(selector)).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('fetch song info when a new song is played', () => {
|
|
||||||
shallowComponent()
|
|
||||||
const song = factory('song')
|
|
||||||
const m = mock(songInfo, 'fetch', song)
|
|
||||||
eventBus.emit('SONG_STARTED', song)
|
|
||||||
expect(m).toHaveBeenCalledWith(song)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -2,7 +2,7 @@ import Component from '@/components/song/SongEditForm.vue'
|
||||||
import Typeahead from '@/components/ui/typeahead.vue'
|
import Typeahead from '@/components/ui/typeahead.vue'
|
||||||
import factory from '@/__tests__/factory'
|
import factory from '@/__tests__/factory'
|
||||||
import { songStore } from '@/stores'
|
import { songStore } from '@/stores'
|
||||||
import { songInfo } from '@/services/info'
|
import { songInfoService } from '@/services/info'
|
||||||
import { mock } from '@/__tests__/__helpers__'
|
import { mock } from '@/__tests__/__helpers__'
|
||||||
import { mount } from '@/__tests__/adapter'
|
import { mount } from '@/__tests__/adapter'
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ describe('components/song/edit-form', () => {
|
||||||
|
|
||||||
it('fetches song information on demand', () => {
|
it('fetches song information on demand', () => {
|
||||||
const song = factory('song', { infoRetrieved: false })
|
const song = factory('song', { infoRetrieved: false })
|
||||||
const fetchMock = mock(songInfo, 'fetch')
|
const fetchMock = mock(songInfoService, 'fetch')
|
||||||
mount(Component, {
|
mount(Component, {
|
||||||
propsData: { songs: song }
|
propsData: { songs: song }
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { beforeEach, expect, it } from 'vitest'
|
||||||
|
import { cleanup, fireEvent } from '@testing-library/vue'
|
||||||
|
import { mockHelper, render } from '@/__tests__/__helpers__'
|
||||||
|
import ExtraPanel from './ExtraPanel.vue'
|
||||||
|
import LyricsPane from '@/__tests__/Stub.vue'
|
||||||
|
import AlbumInfo from '@/__tests__/Stub.vue'
|
||||||
|
import ArtistInfo from '@/__tests__/Stub.vue'
|
||||||
|
import YouTubeVideoList from '@/__tests__/Stub.vue'
|
||||||
|
import factory from '@/__tests__/factory'
|
||||||
|
import { commonStore } from '@/stores'
|
||||||
|
import { songInfoService } from '@/services'
|
||||||
|
import { eventBus } from '@/utils'
|
||||||
|
|
||||||
|
const renderComponent = () => {
|
||||||
|
return render(ExtraPanel, {
|
||||||
|
props: {
|
||||||
|
song: factory<Song>('song')
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
stubs: {
|
||||||
|
LyricsPane,
|
||||||
|
AlbumInfo,
|
||||||
|
ArtistInfo,
|
||||||
|
YouTubeVideoList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cleanup()
|
||||||
|
mockHelper.restoreAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a YouTube tab if using YouTube ', () => {
|
||||||
|
commonStore.state.useYouTube = true
|
||||||
|
const { getByTestId } = renderComponent()
|
||||||
|
|
||||||
|
getByTestId('extra-tab-youtube')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not have a YouTube tab if not using YouTube', async () => {
|
||||||
|
commonStore.state.useYouTube = false
|
||||||
|
const { queryByTestId } = renderComponent()
|
||||||
|
|
||||||
|
expect(await queryByTestId('extra-tab-youtube')).toBe(null)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.each([['extra-tab-lyrics'], ['extra-tab-album'], ['extra-tab-artist']])('switches to "%s" tab', async (testId) => {
|
||||||
|
const { getByTestId, container } = renderComponent()
|
||||||
|
|
||||||
|
await fireEvent.click(getByTestId(testId))
|
||||||
|
|
||||||
|
expect(container.querySelector('[aria-selected=true]')).toBe(getByTestId(testId))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fetches song info when a new song is played', () => {
|
||||||
|
renderComponent()
|
||||||
|
const song = factory<Song>('song')
|
||||||
|
const mock = mockHelper.mock(songInfoService, 'fetch', song)
|
||||||
|
|
||||||
|
eventBus.emit('SONG_STARTED', song)
|
||||||
|
|
||||||
|
expect(mock).toHaveBeenCalledWith(song)
|
||||||
|
})
|
|
@ -6,6 +6,7 @@
|
||||||
id="extraTabLyrics"
|
id="extraTabLyrics"
|
||||||
:aria-selected="currentTab === 'Lyrics'"
|
:aria-selected="currentTab === 'Lyrics'"
|
||||||
aria-controls="extraPanelLyrics"
|
aria-controls="extraPanelLyrics"
|
||||||
|
data-testid="extra-tab-lyrics"
|
||||||
role="tab"
|
role="tab"
|
||||||
@click.prevent="currentTab = 'Lyrics'"
|
@click.prevent="currentTab = 'Lyrics'"
|
||||||
>
|
>
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
id="extraTabArtist"
|
id="extraTabArtist"
|
||||||
:aria-selected="currentTab === 'Artist'"
|
:aria-selected="currentTab === 'Artist'"
|
||||||
aria-controls="extraPanelArtist"
|
aria-controls="extraPanelArtist"
|
||||||
|
data-testid="extra-tab-artist"
|
||||||
role="tab"
|
role="tab"
|
||||||
@click.prevent="currentTab = 'Artist'"
|
@click.prevent="currentTab = 'Artist'"
|
||||||
>
|
>
|
||||||
|
@ -24,6 +26,7 @@
|
||||||
id="extraTabAlbum"
|
id="extraTabAlbum"
|
||||||
:aria-selected="currentTab === 'Album'"
|
:aria-selected="currentTab === 'Album'"
|
||||||
aria-controls="extraPanelAlbum"
|
aria-controls="extraPanelAlbum"
|
||||||
|
data-testid="extra-tab-album"
|
||||||
role="tab"
|
role="tab"
|
||||||
@click.prevent="currentTab = 'Album'"
|
@click.prevent="currentTab = 'Album'"
|
||||||
>
|
>
|
||||||
|
@ -34,6 +37,7 @@
|
||||||
id="extraTabYouTube"
|
id="extraTabYouTube"
|
||||||
:aria-selected="currentTab === 'YouTube'"
|
:aria-selected="currentTab === 'YouTube'"
|
||||||
aria-controls="extraPanelYouTube"
|
aria-controls="extraPanelYouTube"
|
||||||
|
data-testid="extra-tab-youtube"
|
||||||
role="tab"
|
role="tab"
|
||||||
title="YouTube"
|
title="YouTube"
|
||||||
@click.prevent="currentTab = 'YouTube'"
|
@click.prevent="currentTab = 'YouTube'"
|
||||||
|
@ -92,7 +96,7 @@ import isMobile from 'ismobilejs'
|
||||||
import { computed, defineAsyncComponent, ref, toRef, watch } from 'vue'
|
import { computed, defineAsyncComponent, ref, toRef, watch } from 'vue'
|
||||||
import { $, eventBus } from '@/utils'
|
import { $, eventBus } from '@/utils'
|
||||||
import { preferenceStore as preferences } from '@/stores'
|
import { preferenceStore as preferences } from '@/stores'
|
||||||
import { songInfo } from '@/services'
|
import { songInfoService } from '@/services'
|
||||||
import { useThirdPartyServices } from '@/composables'
|
import { useThirdPartyServices } from '@/composables'
|
||||||
|
|
||||||
type Tab = 'Lyrics' | 'Artist' | 'Album' | 'YouTube'
|
type Tab = 'Lyrics' | 'Artist' | 'Album' | 'YouTube'
|
||||||
|
@ -122,7 +126,7 @@ watch(showing, (showingExtraPanel) => {
|
||||||
|
|
||||||
const fetchSongInfo = async (_song: Song) => {
|
const fetchSongInfo = async (_song: Song) => {
|
||||||
try {
|
try {
|
||||||
song.value = await songInfo.fetch(_song)
|
song.value = await songInfoService.fetch(_song)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
song.value = _song
|
song.value = _song
|
||||||
throw err
|
throw err
|
||||||
|
|
|
@ -14,22 +14,22 @@
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<div class="clear" role="tablist">
|
<div class="clear" role="tablist">
|
||||||
<button
|
<button
|
||||||
:aria-selected="currentView === 'details'"
|
|
||||||
@click.prevent="currentView = 'details'"
|
|
||||||
aria-controls="editSongPanelDetails"
|
|
||||||
id="editSongTabDetails"
|
id="editSongTabDetails"
|
||||||
|
:aria-selected="currentView === 'details'"
|
||||||
|
aria-controls="editSongPanelDetails"
|
||||||
role="tab"
|
role="tab"
|
||||||
|
@click.prevent="currentView = 'details'"
|
||||||
>
|
>
|
||||||
Details
|
Details
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click.prevent="currentView = 'lyrics'"
|
|
||||||
v-if="editingOnlyOneSong"
|
v-if="editingOnlyOneSong"
|
||||||
|
id="editSongTabLyrics"
|
||||||
:aria-selected="currentView === 'lyrics'"
|
:aria-selected="currentView === 'lyrics'"
|
||||||
aria-controls="editSongPanelLyrics"
|
aria-controls="editSongPanelLyrics"
|
||||||
id="editSongTabLyrics"
|
|
||||||
role="tab"
|
|
||||||
data-testid="edit-song-lyrics-tab"
|
data-testid="edit-song-lyrics-tab"
|
||||||
|
role="tab"
|
||||||
|
@click.prevent="currentView = 'lyrics'"
|
||||||
>
|
>
|
||||||
Lyrics
|
Lyrics
|
||||||
</button>
|
</button>
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div class="form-row" v-if="editingOnlyOneSong">
|
<div v-if="editingOnlyOneSong" class="form-row">
|
||||||
<label>Title</label>
|
<label>Title</label>
|
||||||
<input v-model="formData.title" v-koel-focus name="title" title="Title" type="text">
|
<input v-model="formData.title" v-koel-focus name="title" title="Title" type="text">
|
||||||
</div>
|
</div>
|
||||||
|
@ -122,7 +122,7 @@ import { computed, defineAsyncComponent, nextTick, reactive, ref, toRef, toRefs
|
||||||
import { isEqual, union } from 'lodash'
|
import { isEqual, union } from 'lodash'
|
||||||
|
|
||||||
import { alerts, arrayify, br2nl, defaultCover, pluralize } from '@/utils'
|
import { alerts, arrayify, br2nl, defaultCover, pluralize } from '@/utils'
|
||||||
import { songInfo } from '@/services/info'
|
import { songInfoService } from '@/services/info'
|
||||||
import { albumStore, artistStore, songStore } from '@/stores'
|
import { albumStore, artistStore, songStore } from '@/stores'
|
||||||
|
|
||||||
interface EditFormData {
|
interface EditFormData {
|
||||||
|
@ -235,7 +235,7 @@ const open = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await songInfo.fetch(firstSong)
|
await songInfoService.fetch(firstSong)
|
||||||
formData.lyrics = br2nl(firstSong.lyrics)
|
formData.lyrics = br2nl(firstSong.lyrics)
|
||||||
formData.track = firstSong.track || null
|
formData.track = firstSong.track || null
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { httpService, albumInfoService, artistInfoService } from '..'
|
import { albumInfoService, artistInfoService, httpService } from '..'
|
||||||
|
|
||||||
interface SongInfoResponse {
|
interface SongInfoResponse {
|
||||||
artist_info: ArtistInfo,
|
artist_info: ArtistInfo,
|
||||||
|
@ -10,14 +10,19 @@ interface SongInfoResponse {
|
||||||
lyrics: string
|
lyrics: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const songInfo = {
|
export const songInfoService = {
|
||||||
fetch: async (song: Song): Promise<Song> => {
|
fetch: async (song: Song) => {
|
||||||
if (!song.infoRetrieved) {
|
if (!song.infoRetrieved) {
|
||||||
const { lyrics, artist_info, album_info, youtube } = await httpService.get<SongInfoResponse>(`song/${song.id}/info`)
|
const {
|
||||||
|
lyrics,
|
||||||
|
artist_info: artistInfo,
|
||||||
|
album_info: albumInfo,
|
||||||
|
youtube
|
||||||
|
} = await httpService.get<SongInfoResponse>(`song/${song.id}/info`)
|
||||||
|
|
||||||
song.lyrics = lyrics
|
song.lyrics = lyrics
|
||||||
artist_info && artistInfoService.merge(song.artist, artist_info)
|
artistInfo && artistInfoService.merge(song.artist, artistInfo)
|
||||||
album_info && albumInfoService.merge(song.album, album_info)
|
albumInfo && albumInfoService.merge(song.album, albumInfo)
|
||||||
song.youtube = youtube
|
song.youtube = youtube
|
||||||
song.infoRetrieved = true
|
song.infoRetrieved = true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue