mirror of
https://github.com/koel/koel
synced 2025-02-17 22:08:28 +00:00
feat(test): add auth service tests
This commit is contained in:
parent
2acd1c2317
commit
3b9f2febd0
11 changed files with 73 additions and 60 deletions
|
@ -1,9 +1,8 @@
|
|||
import isMobile from 'ismobilejs'
|
||||
|
||||
import { loadMainView } from './utils'
|
||||
import { albumStore, artistStore, playlistStore, queueStore, songStore, userStore } from './stores'
|
||||
import { playbackService } from './services'
|
||||
import { use } from '@/utils'
|
||||
import { loadMainView, use } from '@/utils'
|
||||
import { albumStore, artistStore, playlistStore, queueStore, songStore, userStore } from '@/stores'
|
||||
import { playbackService } from '@/services'
|
||||
|
||||
const router = {
|
||||
routes: {
|
||||
|
@ -22,19 +21,19 @@ const router = {
|
|||
'/youtube': () => loadMainView('YouTube'),
|
||||
'/visualizer': () => loadMainView('Visualizer'),
|
||||
'/profile': () => loadMainView('Profile'),
|
||||
'/album/(\\d+)': (id: number) => use(albumStore.byId(~~id)!, album => loadMainView('Album', album)),
|
||||
'/artist/(\\d+)': (id: number) => use(artistStore.byId(~~id)!, artist => loadMainView('Artist', artist)),
|
||||
'/playlist/(\\d+)': (id: number) => use(playlistStore.byId(~~id)!, playlist => loadMainView('Playlist', playlist)),
|
||||
'/song/([a-z0-9]{32})': (id: string) => use(songStore.byId(id)!, song => {
|
||||
'/album/(\\d+)': (id: number) => use(albumStore.byId(~~id), album => loadMainView('Album', album)),
|
||||
'/artist/(\\d+)': (id: number) => use(artistStore.byId(~~id), artist => loadMainView('Artist', artist)),
|
||||
'/playlist/(\\d+)': (id: number) => use(playlistStore.byId(~~id), playlist => loadMainView('Playlist', playlist)),
|
||||
'/song/([a-z0-9]{32})': (id: string) => use(songStore.byId(id), async (song) => {
|
||||
if (isMobile.apple.device) {
|
||||
// Mobile Safari doesn't allow autoplay, so we just queue.
|
||||
queueStore.queue(song)
|
||||
loadMainView('Queue')
|
||||
} else {
|
||||
playbackService.queueAndPlay([song])
|
||||
await playbackService.queueAndPlay([song])
|
||||
}
|
||||
})
|
||||
} as { [path: string]: Closure },
|
||||
},
|
||||
|
||||
init () {
|
||||
this.loadState()
|
||||
|
@ -60,20 +59,16 @@ const router = {
|
|||
* Navigate to a (relative, hash-bang'ed) path.
|
||||
*/
|
||||
go: (path: string | number) => {
|
||||
if (window.__UNIT_TESTING__) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof path === 'number') {
|
||||
window.history.go(path)
|
||||
return
|
||||
}
|
||||
|
||||
if (path[0] !== '/') {
|
||||
if (!path.startsWith('/')) {
|
||||
path = `/${path}`
|
||||
}
|
||||
|
||||
if (path.indexOf('/#!') !== 0) {
|
||||
if (!path.startsWith('/#!')) {
|
||||
path = `/#!${path}`
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
export const audioService = {
|
||||
context: null as AudioContext | null,
|
||||
source: null as MediaElementAudioSourceNode | null,
|
||||
element: null as HTMLMediaElement | null,
|
||||
context: null as unknown as AudioContext,
|
||||
source: null as unknown as MediaElementAudioSourceNode,
|
||||
element: null as unknown as HTMLMediaElement,
|
||||
|
||||
init (element: HTMLMediaElement): void {
|
||||
init (element: HTMLMediaElement) {
|
||||
const AudioContext = window.AudioContext ||
|
||||
window.webkitAudioContext ||
|
||||
window.mozAudioContext ||
|
||||
|
@ -15,15 +15,15 @@ export const audioService = {
|
|||
this.element = element
|
||||
},
|
||||
|
||||
getContext (): AudioContext {
|
||||
return this.context!
|
||||
getContext () {
|
||||
return this.context
|
||||
},
|
||||
|
||||
getSource (): MediaElementAudioSourceNode {
|
||||
return this.source!
|
||||
getSource () {
|
||||
return this.source
|
||||
},
|
||||
|
||||
getElement (): HTMLMediaElement {
|
||||
return this.element!
|
||||
getElement () {
|
||||
return this.element
|
||||
}
|
||||
}
|
||||
|
|
31
resources/assets/js/services/authService.spec.ts
Normal file
31
resources/assets/js/services/authService.spec.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||
import { localStorageService } from '@/services/localStorageService'
|
||||
import { authService } from '@/services/authService'
|
||||
import { expect, it } from 'vitest'
|
||||
|
||||
new class extends UnitTestCase {
|
||||
protected test () {
|
||||
it('gets the token', () => {
|
||||
const mock = this.mock(localStorageService, 'get')
|
||||
authService.getToken()
|
||||
expect(mock).toHaveBeenCalledWith('api-token')
|
||||
})
|
||||
|
||||
it.each([['foo', true], [null, false]])('checks if the token exists', (token, exists) => {
|
||||
this.mock(localStorageService, 'get', token)
|
||||
expect(authService.hasToken()).toBe(exists)
|
||||
})
|
||||
|
||||
it('sets the token', () => {
|
||||
const mock = this.mock(localStorageService, 'set')
|
||||
authService.setToken('foo')
|
||||
expect(mock).toHaveBeenCalledWith('api-token', 'foo')
|
||||
})
|
||||
|
||||
it('destroys the token', () => {
|
||||
const mock = this.mock(localStorageService, 'remove')
|
||||
authService.destroy()
|
||||
expect(mock).toHaveBeenCalledWith('api-token')
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,21 +1,14 @@
|
|||
import { localStorageService } from '.'
|
||||
import { localStorageService } from '@/services'
|
||||
|
||||
const STORAGE_KEY = 'api-token'
|
||||
|
||||
export const authService = {
|
||||
storageKey: 'api-token',
|
||||
|
||||
getToken () {
|
||||
return localStorageService.get<string | null>(this.storageKey)
|
||||
},
|
||||
getToken: () => localStorageService.get<string | null>(STORAGE_KEY),
|
||||
|
||||
hasToken () {
|
||||
return Boolean(this.getToken())
|
||||
},
|
||||
|
||||
setToken (token: string) {
|
||||
localStorageService.set(this.storageKey, token)
|
||||
},
|
||||
|
||||
destroy () {
|
||||
localStorageService.remove(this.storageKey)
|
||||
}
|
||||
setToken: (token: string) => localStorageService.set(STORAGE_KEY, token),
|
||||
destroy: () => localStorageService.remove(STORAGE_KEY)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { favoriteStore, playlistStore } from '@/stores'
|
||||
import { authService } from '.'
|
||||
import { authService } from '@/services'
|
||||
import { arrayify } from '@/utils'
|
||||
|
||||
export const downloadService = {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { secondsToHis } from '@/utils'
|
||||
import { httpService } from '..'
|
||||
import { httpService } from '@/services'
|
||||
|
||||
export const albumInfoService = {
|
||||
async fetch (album: Album): Promise<Album> {
|
||||
async fetch (album: Album) {
|
||||
if (!album.info) {
|
||||
const info = await httpService.get<AlbumInfo|null>(`album/${album.id}/info`)
|
||||
const info = await httpService.get<AlbumInfo | null>(`album/${album.id}/info`)
|
||||
|
||||
if (info) {
|
||||
this.merge(album, info)
|
||||
|
@ -17,7 +17,7 @@ export const albumInfoService = {
|
|||
/**
|
||||
* Merge the (fetched) info into an album.
|
||||
*/
|
||||
merge: (album: Album, info: AlbumInfo): void => {
|
||||
merge: (album: Album, info: AlbumInfo) => {
|
||||
// Convert the duration into i:s
|
||||
if (info.tracks) {
|
||||
info.tracks.forEach(track => {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { httpService } from '..'
|
||||
import { httpService } from '@/services'
|
||||
|
||||
export const artistInfoService = {
|
||||
async fetch (artist: Artist): Promise<Artist> {
|
||||
async fetch (artist: Artist) {
|
||||
if (!artist.info) {
|
||||
const info = await httpService.get<ArtistInfo|null>(`artist/${artist.id}/info`)
|
||||
const info = await httpService.get<ArtistInfo | null>(`artist/${artist.id}/info`)
|
||||
|
||||
if (info) {
|
||||
this.merge(artist, info)
|
||||
|
@ -16,7 +16,7 @@ export const artistInfoService = {
|
|||
/**
|
||||
* Merge the (fetched) info into an artist.
|
||||
*/
|
||||
merge: (artist: Artist, info: ArtistInfo): void => {
|
||||
merge: (artist: Artist, info: ArtistInfo) => {
|
||||
// If the artist image is not in a nice form, discard.
|
||||
if (typeof info.image !== 'string') {
|
||||
info.image = null
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { albumInfoService, artistInfoService, httpService } from '..'
|
||||
import { albumInfoService, artistInfoService, httpService } from '@/services'
|
||||
|
||||
interface SongInfoResponse {
|
||||
artist_info: ArtistInfo,
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
import { get as baseGet, set as baseSet, remove as baseRemove } from 'local-storage'
|
||||
import { get as baseGet, remove as baseRemove, set as baseSet } from 'local-storage'
|
||||
|
||||
export const localStorageService = {
|
||||
get: <T>(key: string, defaultValue: T | null = null): T | null => {
|
||||
get: <T> (key: string, defaultValue: T | null = null): T | null => {
|
||||
const value = baseGet<T>(key)
|
||||
|
||||
return value === null ? defaultValue : value
|
||||
},
|
||||
|
||||
set: <T>(key: string, value: T): boolean => {
|
||||
return baseSet<T>(key, value)
|
||||
},
|
||||
|
||||
remove: (key: string): void => {
|
||||
baseRemove(key)
|
||||
}
|
||||
set: (key: string, value: any) => baseSet(key, value),
|
||||
remove: (key: string) => baseRemove(key)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Pusher from 'pusher-js'
|
||||
|
||||
import { userStore } from '@/stores'
|
||||
import { authService } from '.'
|
||||
import { authService } from '@/services'
|
||||
|
||||
export const socketService = {
|
||||
pusher: null as Pusher.Pusher | null,
|
||||
|
|
1
resources/assets/js/types.d.ts
vendored
1
resources/assets/js/types.d.ts
vendored
|
@ -90,7 +90,6 @@ interface Constructable<T> {
|
|||
|
||||
interface Window {
|
||||
BASE_URL: string
|
||||
__UNIT_TESTING__: boolean
|
||||
readonly PUSHER_APP_KEY: string
|
||||
readonly PUSHER_APP_CLUSTER: string
|
||||
readonly webkitAudioContext: Constructable<AudioContext>
|
||||
|
|
Loading…
Add table
Reference in a new issue