mirror of
https://github.com/koel/koel
synced 2024-11-10 06:34:14 +00:00
feat(test): some missing component tests
This commit is contained in:
parent
6a1a874c23
commit
36e65145aa
13 changed files with 106 additions and 9 deletions
|
@ -1,6 +1,6 @@
|
|||
import isMobile from 'ismobilejs'
|
||||
import { isObject, mergeWith } from 'lodash'
|
||||
import { cleanup, render, RenderOptions } from '@testing-library/vue'
|
||||
import { cleanup, createEvent, fireEvent, render, RenderOptions } from '@testing-library/vue'
|
||||
import { afterEach, beforeEach, vi } from 'vitest'
|
||||
import { defineComponent, nextTick } from 'vue'
|
||||
import { commonStore, userStore } from '@/stores'
|
||||
|
@ -12,6 +12,7 @@ import { routes } from '@/config'
|
|||
import Router from '@/router'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup'
|
||||
import { EventType } from '@testing-library/dom/types/events'
|
||||
|
||||
// A deep-merge function that
|
||||
// - supports symbols as keys (_.merge doesn't)
|
||||
|
@ -184,5 +185,9 @@ export default abstract class UnitTestCase {
|
|||
await this.user.type(element, value)
|
||||
}
|
||||
|
||||
protected async trigger(element: HTMLElement, key: EventType | string, options?: {}) {
|
||||
await fireEvent(element, createEvent[key](element, options))
|
||||
}
|
||||
|
||||
protected abstract test ()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Vitest Snapshot v1
|
||||
|
||||
exports[`renders 1`] = `
|
||||
<article data-v-f01bdc56="" class="relative flex max-w-full md:max-w-[256px] border p-5 rounded-lg flex-col gap-5 transition border-color duration-200 full" draggable="true" tabindex="0" title="IV by Led Zeppelin">
|
||||
<article data-v-f01bdc56="" class="relative flex max-w-full md:max-w-[256px] border p-5 rounded-lg flex-col gap-5 transition border-color duration-200 full" draggable="true" tabindex="0" data-testid="artist-album-card" title="IV by Led Zeppelin">
|
||||
<div data-v-a14c1d10="" data-v-f01bdc56="" class="cover relative w-full aspect-square bg-no-repeat bg-cover bg-center overflow-hidden rounded-md after:block after:pt-[100%]" style="background-image: url(undefined/resources/assets/img/covers/default.svg);" data-testid="album-artist-thumbnail"><img data-v-a14c1d10="" alt="IV" src="http://loremflickr.com/640/480" class="w-full h-full object-cover absolute left-0 top-0 pointer-events-none before:absolute before:w-full before:h-full before:opacity-0 before:z-[1] before-top-0" loading="lazy"><a data-v-a14c1d10="" class="control control-play h-full w-full absolute flex justify-center items-center" role="button"><span data-v-a14c1d10="" class="hidden">Play all songs in the album IV</span><span data-v-a14c1d10="" class="icon opacity-0 w-1/2 h-1/2 flex justify-center items-center pointer-events-none pl-[4%] rounded-full after:w-full after:h-full"></span></a></div>
|
||||
<footer data-v-f01bdc56="" class="flex flex-1 flex-col gap-1.5 overflow-hidden">
|
||||
<div data-v-f01bdc56="" class="name flex flex-col gap-2 whitespace-nowrap"><a href="#/album/42" class="font-medium" data-testid="name">IV</a><a href="#/artist/17">Led Zeppelin</a></div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Vitest Snapshot v1
|
||||
|
||||
exports[`renders 1`] = `
|
||||
<article data-v-f01bdc56="" class="relative flex max-w-full md:max-w-[256px] border p-5 rounded-lg flex-col gap-5 transition border-color duration-200 full" draggable="true" tabindex="0" title="Led Zeppelin">
|
||||
<article data-v-f01bdc56="" class="relative flex max-w-full md:max-w-[256px] border p-5 rounded-lg flex-col gap-5 transition border-color duration-200 full" draggable="true" tabindex="0" data-testid="artist-album-card" title="Led Zeppelin">
|
||||
<div data-v-a14c1d10="" data-v-f01bdc56="" class="cover relative w-full aspect-square bg-no-repeat bg-cover bg-center overflow-hidden rounded-md after:block after:pt-[100%]" style="background-image: url(undefined/resources/assets/img/covers/default.svg);" data-testid="album-artist-thumbnail"><img data-v-a14c1d10="" alt="Led Zeppelin" src="foo.jpg" class="w-full h-full object-cover absolute left-0 top-0 pointer-events-none before:absolute before:w-full before:h-full before:opacity-0 before:z-[1] before-top-0" loading="lazy"><a data-v-a14c1d10="" class="control control-play h-full w-full absolute flex justify-center items-center" role="button"><span data-v-a14c1d10="" class="hidden">Play all songs by Led Zeppelin</span><span data-v-a14c1d10="" class="icon opacity-0 w-1/2 h-1/2 flex justify-center items-center pointer-events-none pl-[4%] rounded-full after:w-full after:h-full"></span></a></div>
|
||||
<footer data-v-f01bdc56="" class="flex flex-1 flex-col gap-1.5 overflow-hidden">
|
||||
<div data-v-f01bdc56="" class="name flex flex-col gap-2 whitespace-nowrap"><a href="#/artist/42" class="font-medium" data-testid="name">Led Zeppelin</a></div>
|
||||
|
|
|
@ -8,7 +8,7 @@ exports[`renders 1`] = `
|
|||
<!--v-if-->
|
||||
</label><label data-v-0b0f87ea="" class="flex flex-col gap-2 text-[1.1rem]">
|
||||
<!--v-if-->
|
||||
<div data-v-0b0f87ea="" class="relative"><input class="block text-base w-full px-4 py-2.5 rounded bg-k-bg-input text-k-text-input read-only:bg-gray-400 read-only:text-gray-900 disabled:bg-gray-400 disabled:text-gray-900 w-full" type="password" placeholder="Password" required=""><button class="absolute p-2.5 right-0 top-0 text-k-bg-primary" type="button"><br data-testid="Icon" icon="[object Object]"></button></div>
|
||||
<div data-v-0b0f87ea="" class="relative"><input class="block text-base w-full px-4 py-2.5 rounded bg-k-bg-input text-k-text-input read-only:bg-gray-400 read-only:text-gray-900 disabled:bg-gray-400 disabled:text-gray-900 w-full" type="password" data-testid="input" placeholder="Password" required=""><button class="absolute p-2.5 right-0 top-0 text-k-bg-primary" type="button" data-testid="toggle"><br data-testid="Icon" icon="[object Object]"></button></div>
|
||||
<!--v-if-->
|
||||
</label><label data-v-0b0f87ea="" class="flex flex-col gap-2 text-[1.1rem]">
|
||||
<!--v-if--><button data-v-8943c846="" data-v-0b0f87ea="" class="text-base text-k-text-primary bg-k-primary px-4 py-2.5 rounded cursor-pointer" type="submit" data-testid="submit">Log In</button>
|
||||
|
@ -31,7 +31,7 @@ exports[`shows Google login button 1`] = `
|
|||
<!--v-if-->
|
||||
</label><label data-v-0b0f87ea="" class="flex flex-col gap-2 text-[1.1rem]">
|
||||
<!--v-if-->
|
||||
<div data-v-0b0f87ea="" class="relative"><input class="block text-base w-full px-4 py-2.5 rounded bg-k-bg-input text-k-text-input read-only:bg-gray-400 read-only:text-gray-900 disabled:bg-gray-400 disabled:text-gray-900 w-full" type="password" placeholder="Password" required=""><button class="absolute p-2.5 right-0 top-0 text-k-bg-primary" type="button"><br data-testid="Icon" icon="[object Object]"></button></div>
|
||||
<div data-v-0b0f87ea="" class="relative"><input class="block text-base w-full px-4 py-2.5 rounded bg-k-bg-input text-k-text-input read-only:bg-gray-400 read-only:text-gray-900 disabled:bg-gray-400 disabled:text-gray-900 w-full" type="password" data-testid="input" placeholder="Password" required=""><button class="absolute p-2.5 right-0 top-0 text-k-bg-primary" type="button" data-testid="toggle"><br data-testid="Icon" icon="[object Object]"></button></div>
|
||||
<!--v-if-->
|
||||
</label><label data-v-0b0f87ea="" class="flex flex-col gap-2 text-[1.1rem]">
|
||||
<!--v-if--><button data-v-8943c846="" data-v-0b0f87ea="" class="text-base text-k-text-primary bg-k-primary px-4 py-2.5 rounded cursor-pointer" type="submit" data-testid="submit">Log In</button>
|
||||
|
|
27
resources/assets/js/components/ui/ArtistAlbumCard.spec.ts
Normal file
27
resources/assets/js/components/ui/ArtistAlbumCard.spec.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { screen } from '@testing-library/vue'
|
||||
import { expect, it } from 'vitest'
|
||||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||
import ArtistAlbumCard from './ArtistAlbumCard.vue'
|
||||
import factory from '@/__tests__/factory'
|
||||
|
||||
new class extends UnitTestCase {
|
||||
protected test () {
|
||||
it('emits events on user actions', async () => {
|
||||
const { emitted } = this.render(ArtistAlbumCard, {
|
||||
props: {
|
||||
entity: factory<Album>('album')
|
||||
}
|
||||
})
|
||||
|
||||
const component = screen.getByTestId('artist-album-card')
|
||||
await this.trigger(component, 'dblClick')
|
||||
expect(emitted().dblclick).toBeTruthy()
|
||||
|
||||
await this.trigger(component, 'dragStart')
|
||||
expect(emitted().dragstart).toBeTruthy()
|
||||
|
||||
await this.trigger(component, 'contextMenu')
|
||||
expect(emitted().contextmenu).toBeTruthy()
|
||||
})
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
:class="layout"
|
||||
draggable="true"
|
||||
tabindex="0"
|
||||
data-testid="artist-album-card"
|
||||
@dblclick="onDblClick"
|
||||
@dragstart="onDragStart"
|
||||
@contextmenu.prevent="onContextMenu"
|
||||
|
|
|
@ -32,7 +32,7 @@ const value = computed({
|
|||
})
|
||||
|
||||
/**
|
||||
* Since watching the value and update the slider UI proves to be not performant,
|
||||
* Since watching the value and updating the slider UI proves to be not performant,
|
||||
* we defined an explicit method to update the UI and expose it so that the
|
||||
* parent component (Equalizer) can call it when resetting the preset.
|
||||
*/
|
||||
|
|
|
@ -16,7 +16,7 @@ new class extends UnitTestCase {
|
|||
it('emits the input event', async () => {
|
||||
const { emitted } = this.render(CheckBox)
|
||||
|
||||
await this.user.click(screen.getByRole('checkbox'))
|
||||
await this.trigger(screen.getByRole('checkbox'), 'click')
|
||||
|
||||
expect(emitted()['update:modelValue']).toBeTruthy()
|
||||
})
|
||||
|
|
20
resources/assets/js/components/ui/form/PasswordField.spec.ts
Normal file
20
resources/assets/js/components/ui/form/PasswordField.spec.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { screen } from '@testing-library/vue'
|
||||
import { expect, it } from 'vitest'
|
||||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||
import PasswordField from './PasswordField.vue'
|
||||
|
||||
new class extends UnitTestCase {
|
||||
protected test () {
|
||||
it('renders plain text', async () => {
|
||||
this.render(PasswordField)
|
||||
const input = screen.getByTestId('input')
|
||||
const toggle = screen.getByTestId('toggle')
|
||||
|
||||
await this.trigger(toggle, 'click')
|
||||
expect(input.getAttribute('type')).toBe('text')
|
||||
|
||||
await this.trigger(toggle, 'click')
|
||||
expect(input.getAttribute('type')).toBe('password')
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
<template>
|
||||
<div class="relative">
|
||||
<TextInput v-model="value" :type="type" class="w-full" v-bind="$attrs" />
|
||||
<button class="absolute p-2.5 right-0 top-0 text-k-bg-primary" type="button" @click.prevent="toggleReveal">
|
||||
<TextInput v-model="value" :type="type" class="w-full" data-testid="input" v-bind="$attrs" />
|
||||
<button
|
||||
class="absolute p-2.5 right-0 top-0 text-k-bg-primary"
|
||||
type="button"
|
||||
data-testid="toggle"
|
||||
@click.prevent="toggleReveal"
|
||||
>
|
||||
<Icon v-if="type === 'password'" :icon="faEye" />
|
||||
<Icon v-else :icon="faEyeSlash" />
|
||||
</button>
|
||||
|
|
19
resources/assets/js/components/ui/form/TextArea.spec.ts
Normal file
19
resources/assets/js/components/ui/form/TextArea.spec.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { screen } from '@testing-library/vue'
|
||||
import { expect, it } from 'vitest'
|
||||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||
import TextArea from './TextArea.vue'
|
||||
|
||||
new class extends UnitTestCase {
|
||||
protected test () {
|
||||
it('emits value', async () => {
|
||||
const { emitted } = this.render(TextArea)
|
||||
|
||||
await this.type(screen.getByRole('textbox'), 'Hi')
|
||||
|
||||
expect(emitted()['update:modelValue']).toStrictEqual([
|
||||
['H'],
|
||||
['Hi']
|
||||
])
|
||||
})
|
||||
}
|
||||
}
|
19
resources/assets/js/components/ui/form/TextInput.spec.ts
Normal file
19
resources/assets/js/components/ui/form/TextInput.spec.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { screen } from '@testing-library/vue'
|
||||
import { expect, it } from 'vitest'
|
||||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||
import TextInput from './TextInput.vue'
|
||||
|
||||
new class extends UnitTestCase {
|
||||
protected test () {
|
||||
it('emits value', async () => {
|
||||
const { emitted } = this.render(TextInput)
|
||||
|
||||
await this.type(screen.getByRole('textbox'), 'Hi')
|
||||
|
||||
expect(emitted()['update:modelValue']).toStrictEqual([
|
||||
['H'],
|
||||
['Hi']
|
||||
])
|
||||
})
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { uuid } from '@/utils'
|
||||
|
||||
import MessageToast from '@/components/ui/message-toaster/MessageToast.vue'
|
||||
|
||||
const messages = ref<ToastMessage[]>([])
|
||||
|
|
Loading…
Reference in a new issue