feat(test): add auth service tests

This commit is contained in:
Phan An 2022-05-14 20:49:45 +02:00
parent 2acd1c2317
commit 3b9f2febd0
No known key found for this signature in database
GPG key ID: A81E4477F0BB6FDC
11 changed files with 73 additions and 60 deletions

View file

@ -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}`
}

View file

@ -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
}
}

View 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')
})
}
}

View file

@ -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)
}

View file

@ -1,5 +1,5 @@
import { favoriteStore, playlistStore } from '@/stores'
import { authService } from '.'
import { authService } from '@/services'
import { arrayify } from '@/utils'
export const downloadService = {

View file

@ -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 => {

View file

@ -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

View file

@ -1,4 +1,4 @@
import { albumInfoService, artistInfoService, httpService } from '..'
import { albumInfoService, artistInfoService, httpService } from '@/services'
interface SongInfoResponse {
artist_info: ArtistInfo,

View file

@ -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)
}

View file

@ -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,

View file

@ -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>