mirror of
https://github.com/koel/koel
synced 2024-11-10 06:34:14 +00:00
feat(test): add LyricsPane component tests
This commit is contained in:
parent
9805ad1e44
commit
e3145d2a97
7 changed files with 92 additions and 22 deletions
|
@ -4,7 +4,8 @@ import { cleanup, render, RenderOptions } from '@testing-library/vue'
|
|||
import { afterEach, beforeEach, vi } from 'vitest'
|
||||
import { clickaway, droppable, focus } from '@/directives'
|
||||
import { defineComponent, nextTick } from 'vue'
|
||||
import { commonStore } from '@/stores'
|
||||
import { commonStore, userStore } from '@/stores'
|
||||
import factory from '@/__tests__/factory'
|
||||
|
||||
declare type Methods<T> = { [K in keyof T]: T[K] extends Closure ? K : never; }[keyof T] & (string | symbol);
|
||||
|
||||
|
@ -34,6 +35,15 @@ export default abstract class ComponentTestCase {
|
|||
})
|
||||
}
|
||||
|
||||
protected actingAs (user: User) {
|
||||
userStore.state.current = user
|
||||
return this
|
||||
}
|
||||
|
||||
protected actingAsAdmin () {
|
||||
return this.actingAs(factory.states('admin')<User>('user'))
|
||||
}
|
||||
|
||||
protected mock<T, M extends Methods<Required<T>>> (obj: T, methodName: M, implementation?: any) {
|
||||
const mock = vi.fn()
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ import { fireEvent, queryAllByTestId } from '@testing-library/vue'
|
|||
import { eventBus } from '@/utils'
|
||||
import isMobile from 'ismobilejs'
|
||||
import compareVersions from 'compare-versions'
|
||||
import { userStore } from '@/stores'
|
||||
import factory from '@/__tests__/factory'
|
||||
import ComponentTestCase from '@/__tests__/ComponentTestCase'
|
||||
import AppHeader from './AppHeader.vue'
|
||||
import SearchForm from '@/components/ui/SearchForm.vue'
|
||||
|
@ -44,9 +42,8 @@ new class extends ComponentTestCase {
|
|||
'announces a new version if applicable',
|
||||
async (hasNewVersion, isAdmin, announcing) => {
|
||||
this.mock(compareVersions, 'compare', hasNewVersion)
|
||||
userStore.state.current = factory<User>('user', { is_admin: isAdmin })
|
||||
|
||||
const { queryAllByTestId } = this.render(AppHeader)
|
||||
const { queryAllByTestId } = this.actingAsAdmin().render(AppHeader)
|
||||
|
||||
expect(await queryAllByTestId('new-version')).toHaveLength(announcing ? 1 : 0)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { expect, it } from 'vitest'
|
||||
import { commonStore, userStore } from '@/stores'
|
||||
import factory from '@/__tests__/factory'
|
||||
import { commonStore } from '@/stores'
|
||||
import ComponentTestCase from '@/__tests__/ComponentTestCase'
|
||||
import AboutKoelModel from './AboutKoelModal.vue'
|
||||
import Btn from '@/components/ui/Btn.vue'
|
||||
|
@ -29,8 +28,7 @@ new class extends ComponentTestCase {
|
|||
it('shows new version', () => {
|
||||
commonStore.state.currentVersion = 'v1.0.0'
|
||||
commonStore.state.latestVersion = 'v1.0.1'
|
||||
userStore.state.current = factory.states('admin')<User>('user')
|
||||
const { findByTestId } = this.render(AboutKoelModel)
|
||||
const { findByTestId } = this.actingAsAdmin().render(AboutKoelModel)
|
||||
|
||||
findByTestId('new-version-about')
|
||||
})
|
||||
|
|
53
resources/assets/js/components/ui/LyricsPane.spec.ts
Normal file
53
resources/assets/js/components/ui/LyricsPane.spec.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { expect, it } from 'vitest'
|
||||
import ComponentTestCase from '@/__tests__/ComponentTestCase'
|
||||
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 {
|
||||
private renderComponent (song?: Song) {
|
||||
song = song || factory<Song>('song', {
|
||||
lyrics: 'Foo bar baz qux'
|
||||
})
|
||||
|
||||
return this.render(LyricsPane, {
|
||||
props: {
|
||||
song
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
TextMagnifier
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
protected test () {
|
||||
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 mock = this.mock(eventBus, 'emit')
|
||||
const { getByTestId } = this.actingAsAdmin().renderComponent(song)
|
||||
|
||||
await fireEvent.click(getByTestId('add-lyrics-btn'))
|
||||
|
||||
expect(mock).toHaveBeenCalledWith('MODAL_SHOW_EDIT_SONG_FORM', song, 'lyrics')
|
||||
})
|
||||
|
||||
it('does not have a button to add lyrics if current user is not an admin', async () => {
|
||||
const { queryByTestId } = this.actingAs(factory<User>('user')).renderComponent(factory<Song>('song', {
|
||||
lyrics: null
|
||||
}))
|
||||
|
||||
expect(await queryByTestId('add-lyrics-btn')).toBeNull()
|
||||
})
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
<template v-if="song">
|
||||
<div v-show="song.lyrics">
|
||||
<div ref="lyricsContainer" v-html="song.lyrics"></div>
|
||||
<Magnifier :target="lyricsContainer"/>
|
||||
<TextMagnifier :target="lyricsContainer" class="magnifier"/>
|
||||
</div>
|
||||
<p v-if="song.id && !song.lyrics" class="none text-secondary">
|
||||
<template v-if="isAdmin">
|
||||
|
@ -26,7 +26,7 @@ import { defineAsyncComponent, ref, toRefs } from 'vue'
|
|||
import { eventBus } from '@/utils'
|
||||
import { useAuthorization } from '@/composables'
|
||||
|
||||
const Magnifier = defineAsyncComponent(() => import('@/components/ui/TextMagnifier.vue'))
|
||||
const TextMagnifier = defineAsyncComponent(() => import('@/components/ui/TextMagnifier.vue'))
|
||||
|
||||
const props = defineProps<{ song: Song }>()
|
||||
const { song } = toRefs(props)
|
||||
|
@ -43,7 +43,7 @@ const showEditSongForm = () => eventBus.emit('MODAL_SHOW_EDIT_SONG_FORM', song.v
|
|||
line-height: 1.6;
|
||||
position: relative;
|
||||
|
||||
.text-zoomer {
|
||||
.magnifier {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -54,7 +54,7 @@ const showEditSongForm = () => eventBus.emit('MODAL_SHOW_EDIT_SONG_FORM', song.v
|
|||
}
|
||||
}
|
||||
|
||||
&:hover .text-zoomer {
|
||||
&:hover .magnifier {
|
||||
opacity: .5;
|
||||
|
||||
&:hover {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<div class="text-zoomer">
|
||||
<button title="Zoom out" @click.prevent="zoom(-1)">
|
||||
<i class="fa fa-search-minus"></i>
|
||||
<span>
|
||||
<button title="Zoom out" type="button" @click.prevent="zoom(-1)">
|
||||
<i class="fa fa-search-minus"/>
|
||||
</button>
|
||||
<button title="Zoom in" @click.prevent="zoom(1)">
|
||||
<i class="fa fa-search-plus"></i>
|
||||
<button title="Zoom in" type="button" @click.prevent="zoom(1)">
|
||||
<i class="fa fa-search-plus"/>
|
||||
</button>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
@ -33,7 +33,7 @@ const zoom = (level: number) => {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.text-zoomer {
|
||||
span {
|
||||
display: flex;
|
||||
transition: .2s;
|
||||
|
||||
|
@ -53,12 +53,12 @@ const zoom = (level: number) => {
|
|||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
&:first-of-type {
|
||||
&:first-child {
|
||||
border-radius: 4px 0 0 4px;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
&:last-child {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// Vitest Snapshot v1
|
||||
|
||||
exports[`renders 1`] = `
|
||||
"<article id=\\"lyrics\\" data-v-502c43f0=\\"\\">
|
||||
<div class=\\"content\\" data-v-502c43f0=\\"\\">
|
||||
<div data-v-502c43f0=\\"\\">
|
||||
<div data-v-502c43f0=\\"\\">Foo bar baz qux</div><span class=\\"magnifier\\" data-v-4cadbfe6=\\"\\" data-v-502c43f0=\\"\\"><button title=\\"Zoom out\\" type=\\"button\\" data-v-4cadbfe6=\\"\\"><i class=\\"fa fa-search-minus\\" data-v-4cadbfe6=\\"\\"></i></button><button title=\\"Zoom in\\" type=\\"button\\" data-v-4cadbfe6=\\"\\"><i class=\\"fa fa-search-plus\\" data-v-4cadbfe6=\\"\\"></i></button></span>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</article>"
|
||||
`;
|
Loading…
Reference in a new issue