Restores front tests using jest and vite

1749-smtp-uri-configuration
Marcos 2022-03-15 21:12:54 +01:00 zatwierdzone przez Georg Krause
rodzic 8b0d4049d4
commit f3d998c7e0
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 2970D504B2183D22
19 zmienionych plików z 1396 dodań i 4 usunięć

Wyświetl plik

@ -0,0 +1,17 @@
module.exports = {
presets: [
'@babel/preset-env',
],
plugins: [
'@babel/plugin-transform-runtime',
function () {
return {
visitor: {
MetaProperty(path) {
path.replaceWithSourceString('process')
},
},
}
},
],
}

Wyświetl plik

@ -9,7 +9,7 @@
"build": "vite build",
"build:deployment": "vite build --base /front/",
"serve": "vite preview",
"test:unit": "true",
"test:unit": "jest",
"lint": "eslint --ext .js,.vue src",
"fix-fomantic-css": "scripts/fix-fomantic-css.sh",
"i18n-compile": "scripts/i18n-compile.sh",
@ -45,7 +45,14 @@
"vuex-router-sync": "5.0.0"
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@vue/test-utils": "^1.0.0-beta.22",
"autoprefixer": "10.4.4",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^27.5.1",
"chai": "^4.3.6",
"easygettext": "2.17.0",
"eslint": "8.11.0",
"eslint-config-standard": "16.0.3",
@ -55,8 +62,12 @@
"eslint-plugin-promise": "6.0.0",
"eslint-plugin-vue": "7.20.0",
"glob-all": "3.3.0",
"jest-cli": "^27.5.1",
"moxios": "^0.4.0",
"sinon": "^13.0.1",
"vite": "2.8.6",
"vite-plugin-vue2": "1.9.3",
"vue-jest": "^3.0.7",
"vue-template-compiler": "2.6.14"
},
"resolutions": {
@ -109,5 +120,20 @@
"iOS >= 9",
"Android >= 4",
"not dead"
]
],
"jest": {
"moduleFileExtensions": [
"js",
"json",
"vue"
],
"transform": {
".*\\.(vue)$": "vue-jest",
"^.+\\.js$": "babel-jest"
},
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
},
"testEnvironment": "jsdom"
}
}

Wyświetl plik

@ -2,7 +2,6 @@ import Vue from 'vue'
import axios from 'axios'
import logger from '@/logging'
import lodash from 'lodash'
import router from '@/router'
function getDefaultScopedTokens () {
return {
@ -142,7 +141,9 @@ export default {
// commit('token', response.data.token)
dispatch('fetchProfile').then(() => {
// Redirect to a specified route
return router.push(next)
import('@/router').then((router) => {
return router.default.push(next)
})
})
}, response => {
logger.default.error('Error while logging in', response.data)

Wyświetl plik

@ -0,0 +1,9 @@
{
"env": {
"mocha": true
},
"globals": {
"expect": true,
"sinon": true
}
}

Wyświetl plik

@ -0,0 +1,25 @@
import { expect } from 'chai'
import { toLinearVolumeScale, toLogarithmicVolumeScale } from '@/audio/volume'
describe('store/auth', () => {
describe('toLinearVolumeScale', () => {
it('it should return real 0', () => {
expect(toLinearVolumeScale(0.0)).to.equal(0.0)
})
it('it should return full volume', () => {
expect(toLinearVolumeScale(1.0)).to.be.closeTo(1.0, 0.001)
})
})
describe('toLogarithmicVolumeScale', () => {
it('it should return real 0', () => {
expect(toLogarithmicVolumeScale(0.0)).to.equal(0.0)
})
it('it should return full volume', () => {
expect(toLogarithmicVolumeScale(1.0)).to.be.closeTo(1.0, 0.001)
})
})
})

Wyświetl plik

@ -0,0 +1,12 @@
import {expect} from 'chai'
import Username from '@/components/common/Username.vue'
import { render } from '../../utils'
describe('Username', () => {
it('displays username', () => {
const vm = render(Username, {username: 'Hello'})
expect(vm.$el.textContent).to.equal('Hello')
})
})

Wyświetl plik

@ -0,0 +1,42 @@
import { expect } from 'chai'
import PasswordInput from '@/components/forms/PasswordInput.vue'
import { shallowMount } from '@vue/test-utils'
const sinon = require('sinon')
describe('PasswordInput', () => {
const password = 'password'
let sandbox
beforeEach(function () {
sandbox = sinon.createSandbox()
})
afterEach(function () {
sandbox.restore()
})
const wrapper = shallowMount(PasswordInput, {
mocks: {
$pgettext: () => 'dummy',
$store: {
commit: () => { }
},
},
propsData: {
fieldId: 'password',
value: password,
}
})
wrapper.setProps({ value: password, copyButton: true })
it('password input has passed value', () => {
const inputElement = wrapper.find('input')
expect(inputElement.element.value).to.equal(password)
})
it('copy password function called', () => {
document.execCommand = jest.fn()
const spy = sandbox.spy(wrapper.vm, 'copyPassword')
sandbox.stub(PasswordInput.methods, '_copyStringToClipboard').callsFake()
const copyButton = wrapper.findAll('button').at(1)
copyButton.trigger('click')
sandbox.assert.calledOnce(spy)
})
})

Wyświetl plik

@ -0,0 +1,52 @@
import {expect} from 'chai'
import moment from 'moment'
import {truncate, ago, capitalize, year} from '@/filters'
describe('filters', () => {
describe('truncate', () => {
it('leave strings as it if correct size', () => {
const input = 'Hello world'
let output = truncate(input, 100)
expect(output).to.equal(input)
})
it('returns shorter string with character', () => {
const input = 'Hello world'
let output = truncate(input, 5)
expect(output).to.equal('Hello…')
})
it('custom ellipsis', () => {
const input = 'Hello world'
let output = truncate(input, 5, ' pouet')
expect(output).to.equal('Hello pouet')
})
})
describe('ago', () => {
it('works', () => {
const input = new Date()
let output = ago(input)
let expected = moment(input).calendar(input, {
sameDay: 'LT',
nextDay: 'L',
nextWeek: 'L',
lastDay: 'L',
lastWeek: 'L',
sameElse: 'L'
})
expect(output).to.equal(expected)
})
})
describe('year', () => {
it('works', () => {
const input = '2017-07-13'
let output = year(input)
expect(output).to.equal(2017)
})
})
describe('capitalize', () => {
it('works', () => {
const input = 'hello world'
let output = capitalize(input)
expect(output).to.equal('Hello world')
})
})
})

Wyświetl plik

@ -0,0 +1,65 @@
import {expect} from 'chai'
import {normalizeQuery, parseTokens, compileTokens} from '@/search'
describe('search', () => {
it('normalizeQuery returns correct tokens', () => {
const input = 'this is a "search query" yeah'
let output = normalizeQuery(input)
expect(output).to.deep.equal(['this', 'is', 'a', 'search query', 'yeah'])
})
it('parseTokens can extract fields and values from tokens', () => {
const input = ['unhandled', 'key:value', 'status:pending', 'title:"some title"', 'anotherunhandled']
let output = parseTokens(input)
let expected = [
{
'field': null,
'value': 'unhandled'
},
{
'field': 'key',
'value': 'value'
},
{
'field': 'status',
'value': 'pending',
},
{
'field': 'title',
'value': 'some title'
},
{
'field': null,
'value': 'anotherunhandled'
}
]
expect(output).to.deep.equal(expected)
})
it('compileTokens returns proper query string', () => {
let input = [
{
'field': null,
'value': 'unhandled'
},
{
'field': 'key',
'value': 'value'
},
{
'field': 'status',
'value': 'pending',
},
{
'field': 'title',
'value': 'some title'
},
{
'field': null,
'value': 'anotherunhandled'
}
]
const expected = 'unhandled key:value status:pending title:"some title" anotherunhandled'
let output = compileTokens(input)
expect(output).to.deep.equal(expected)
})
})

Wyświetl plik

@ -0,0 +1,174 @@
var sinon = require('sinon')
import {expect} from 'chai'
import moxios from 'moxios'
import store from '@/store/auth'
import { testAction } from '../../utils'
describe('store/auth', () => {
var sandbox
beforeEach(function () {
sandbox = sinon.createSandbox()
moxios.install()
})
afterEach(function () {
sandbox.restore()
moxios.uninstall()
})
describe('mutations', () => {
it('profile', () => {
const state = {}
store.mutations.profile(state, {})
expect(state.profile).to.deep.equal({})
})
it('username', () => {
const state = {}
store.mutations.username(state, 'world')
expect(state.username).to.equal('world')
})
it('authenticated true', () => {
const state = {}
store.mutations.authenticated(state, true)
expect(state.authenticated).to.equal(true)
})
it('authenticated false', () => {
const state = {
username: 'dummy',
token: 'dummy',
profile: 'dummy',
availablePermissions: 'dummy'
}
store.mutations.authenticated(state, false)
expect(state.authenticated).to.equal(false)
expect(state.username).to.equal(null)
expect(state.token).to.equal(null)
expect(state.profile).to.equal(null)
expect(state.availablePermissions).to.deep.equal({})
})
it('token null', () => {
const state = {}
store.mutations.token(state, null)
expect(state.token).to.equal(null)
})
it('token real', () => {
const state = {}
let token = 'eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2p3dC1pZHAuZXhhbXBsZS5jb20iLCJzdWIiOiJtYWlsdG86bWlrZUBleGFtcGxlLmNvbSIsIm5iZiI6MTUxNTUzMzQyOSwiZXhwIjoxNTE1NTM3MDI5LCJpYXQiOjE1MTU1MzM0MjksImp0aSI6ImlkMTIzNDU2IiwidHlwIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9yZWdpc3RlciJ9.'
store.mutations.token(state, token)
expect(state.token).to.equal(token)
})
it('permissions', () => {
const state = { availablePermissions: {} }
store.mutations.permission(state, {key: 'admin', status: true})
expect(state.availablePermissions).to.deep.equal({admin: true})
})
})
describe('getters', () => {
it('header', () => {
const state = { oauth: {accessToken: 'helloworld' }}
expect(store.getters['header'](state)).to.equal('Bearer helloworld')
})
})
describe('actions', () => {
it('logout', () => {
testAction({
action: store.actions.logout,
params: {state: {}},
expectedMutations: [
{ type: 'auth/reset', payload: null, options: {root: true} },
{ type: 'favorites/reset', payload: null, options: {root: true} },
{ type: 'player/reset', payload: null, options: {root: true} },
{ type: 'playlists/reset', payload: null, options: {root: true} },
{ type: 'queue/reset', payload: null, options: {root: true} },
{ type: 'radios/reset', payload: null, options: {root: true} }
]
})
})
it('check jwt null', () => {
testAction({
action: store.actions.check,
params: {state: {}},
expectedMutations: [
{ type: 'authenticated', payload: false },
{ type: 'authenticated', payload: true },
],
expectedActions: [
{ type: 'fetchProfile' },
]
})
})
it('login success', () => {
moxios.stubRequest('token/', {
status: 200,
response: {
token: 'test'
}
})
const credentials = {
username: 'bob'
}
testAction({
action: store.actions.login,
payload: {credentials: credentials},
expectedMutations: [
{ type: 'token', payload: 'test' }
],
expectedActions: [
{ type: 'fetchProfile' }
]
})
})
it('login error', () => {
moxios.stubRequest('token/', {
status: 500,
response: {
token: 'test'
}
})
const credentials = {
username: 'bob'
}
let spy = sandbox.spy()
testAction({
action: store.actions.login,
payload: {credentials: credentials, onError: spy}
}, () => {
expect(spy.calledOnce).to.equal(true)
done() // eslint-disable-line no-undef
})
})
it('fetchProfile', () => {
const profile = {
username: 'bob',
permissions: {
admin: true
}
}
moxios.stubRequest('users/me/', {
status: 200,
response: profile
})
testAction({
action: store.actions.fetchProfile,
expectedMutations: [
{ type: 'authenticated', payload: true },
{ type: 'profile', payload: profile },
{ type: 'username', payload: profile.username },
{ type: 'permission', payload: {key: 'admin', status: true} }
],
expectedActions: [
{ type: 'ui/initSettings', payload: { root: true } },
{ type: 'updateProfile', payload: profile },
{ type: 'ui/fetchUnreadNotifications', payload: null },
{ type: 'favorites/fetch', payload: null, options: {root: true} },
{ type: 'channels/fetchSubscriptions', payload: null, options: {root: true} },
{ type: 'libraries/fetchFollows', payload: null, options: {root: true} },
{ type: 'moderation/fetchContentFilters', payload: null, options: {root: true} },
{ type: 'playlists/fetchOwn', payload: null, options: {root: true} }
]
})
})
})
})

Wyświetl plik

@ -0,0 +1,54 @@
import {expect} from 'chai'
import store from '@/store/favorites'
import { testAction } from '../../utils'
describe('store/favorites', () => {
describe('mutations', () => {
it('track true', () => {
const state = { tracks: [] }
store.mutations.track(state, {id: 1, value: true})
expect(state.tracks).to.deep.equal([1])
expect(state.count).to.deep.equal(1)
})
it('track false', () => {
const state = { tracks: [1] }
store.mutations.track(state, {id: 1, value: false})
expect(state.tracks).to.deep.equal([])
expect(state.count).to.deep.equal(0)
})
})
describe('getters', () => {
it('isFavorite true', () => {
const state = { tracks: [1] }
expect(store.getters['isFavorite'](state)(1)).to.equal(true)
})
it('isFavorite false', () => {
const state = { tracks: [] }
expect(store.getters['isFavorite'](state)(1)).to.equal(false)
})
})
describe('actions', () => {
it('toggle true', () => {
testAction({
action: store.actions.toggle,
payload: 1,
params: {getters: {isFavorite: () => false}},
expectedActions: [
{ type: 'set', payload: {id: 1, value: true} }
]
})
})
it('toggle true', () => {
testAction({
action: store.actions.toggle,
payload: 1,
params: {getters: {isFavorite: () => true}},
expectedActions: [
{ type: 'set', payload: {id: 1, value: false} }
]
})
})
})
})

Wyświetl plik

@ -0,0 +1,81 @@
import {expect} from 'chai'
var sinon = require('sinon')
import axios from 'axios'
import moxios from 'moxios'
import store from '@/store/instance'
import { testAction } from '../../utils'
describe('store/instance', () => {
var sandbox
beforeEach(function () {
sandbox = sinon.createSandbox()
moxios.install()
})
afterEach(function () {
sandbox.restore()
moxios.uninstall()
axios.defaults.baseURL = null
})
describe('mutations', () => {
it('settings', () => {
const state = {settings: {users: {upload_quota: {value: 1}}}}
let settings = {users: {registration_enabled: {value: true}}}
store.mutations.settings(state, settings)
expect(state.settings).to.deep.equal({
users: {upload_quota: {value: 1}, registration_enabled: {value: true}}
})
})
it('instanceUrl', () => {
const state = {instanceUrl: null, knownInstances: ['http://test2/', 'http://test/']}
store.mutations.instanceUrl(state, 'http://test')
expect(state).to.deep.equal({
instanceUrl: 'http://test/', // trailing slash added
knownInstances: ['http://test/', 'http://test2/']
})
})
})
describe('actions', () => {
it('fetchSettings', () => {
moxios.stubRequest('instance/settings/', {
status: 200,
response: [
{
section: 'users',
name: 'upload_quota',
value: 1
},
{
section: 'users',
name: 'registration_enabled',
value: false
}
]
})
testAction({
action: store.actions.fetchSettings,
payload: null,
expectedMutations: [
{
type: 'settings',
payload: {
users: {
upload_quota: {
section: 'users',
name: 'upload_quota',
value: 1
},
registration_enabled: {
section: 'users',
name: 'registration_enabled',
value: false
}
}
}
}
]
})
})
})
})

Wyświetl plik

@ -0,0 +1,214 @@
import {expect} from 'chai'
import store from '@/store/player'
import { testAction } from '../../utils'
describe('store/player', () => {
describe('mutations', () => {
it('set volume', () => {
const state = { volume: 0 }
store.mutations.volume(state, 0.9)
expect(state.volume).to.equal(0.9)
})
it('set volume max 1', () => {
const state = { volume: 0 }
store.mutations.volume(state, 2)
expect(state.volume).to.equal(1)
})
it('set volume min to 0', () => {
const state = { volume: 0.5 }
store.mutations.volume(state, -2)
expect(state.volume).to.equal(0)
})
it('increment volume', () => {
const state = { volume: 0 }
store.mutations.incrementVolume(state, 0.1)
expect(state.volume).to.equal(0.1)
})
it('increment volume max 1', () => {
const state = { volume: 0 }
store.mutations.incrementVolume(state, 2)
expect(state.volume).to.equal(1)
})
it('increment volume min to 0', () => {
const state = { volume: 0.5 }
store.mutations.incrementVolume(state, -2)
expect(state.volume).to.equal(0)
})
it('set duration', () => {
const state = { duration: 42 }
store.mutations.duration(state, 14)
expect(state.duration).to.equal(14)
})
it('set errored', () => {
const state = { errored: false }
store.mutations.errored(state, true)
expect(state.errored).to.equal(true)
})
it('set looping', () => {
const state = { looping: 1 }
store.mutations.looping(state, 2)
expect(state.looping).to.equal(2)
})
it('set playing', () => {
const state = { playing: false }
store.mutations.playing(state, true)
expect(state.playing).to.equal(true)
})
it('set current time', () => {
const state = { currentTime: 1 }
store.mutations.currentTime(state, 2)
expect(state.currentTime).to.equal(2)
})
it('toggle looping from 0', () => {
const state = { looping: 0 }
store.mutations.toggleLooping(state)
expect(state.looping).to.equal(1)
})
it('toggle looping from 1', () => {
const state = { looping: 1 }
store.mutations.toggleLooping(state)
expect(state.looping).to.equal(2)
})
it('toggle looping from 2', () => {
const state = { looping: 2 }
store.mutations.toggleLooping(state)
expect(state.looping).to.equal(0)
})
it('increment error count', () => {
const state = { errorCount: 0 }
store.mutations.incrementErrorCount(state)
expect(state.errorCount).to.equal(1)
})
it('reset error count', () => {
const state = { errorCount: 10 }
store.mutations.resetErrorCount(state)
expect(state.errorCount).to.equal(0)
})
})
describe('getters', () => {
it('durationFormatted', () => {
const state = { duration: 12.51 }
expect(store.getters['durationFormatted'](state)).to.equal('0:13')
})
it('currentTimeFormatted', () => {
const state = { currentTime: 12.51 }
expect(store.getters['currentTimeFormatted'](state)).to.equal('0:13')
})
it('progress', () => {
const state = { currentTime: 4, duration: 10 }
expect(store.getters['progress'](state)).to.equal(40)
})
})
describe('actions', () => {
it('incrementVolume', () => {
testAction({
action: store.actions.incrementVolume,
payload: 0.2,
params: {state: {volume: 0.7}},
expectedMutations: [
{ type: 'volume', payload: 0.7 + 0.2 }
]
})
})
it('toggle playback false', () => {
testAction({
action: store.actions.togglePlayback,
params: {state: {playing: false}},
expectedMutations: [
{ type: 'playing', payload: true }
]
})
})
it('toggle playback true', () => {
testAction({
action: store.actions.togglePlayback,
params: {state: {playing: true}},
expectedMutations: [
{ type: 'playing', payload: false }
]
})
})
it('resume playback', () => {
testAction({
action: store.actions.resumePlayback,
params: {state: {}},
expectedMutations: [
{ type: 'playing', payload: true }
]
})
})
it('pause playback', () => {
testAction({
action: store.actions.pausePlayback,
expectedMutations: [
{ type: 'playing', payload: false }
]
})
})
it('trackEnded', () => {
testAction({
action: store.actions.trackEnded,
payload: {test: 'track'},
params: {rootState: {queue: {currentIndex: 0, tracks: [1, 2]}}},
expectedActions: [
{ type: 'queue/next', payload: null, options: {root: true} }
]
})
})
it('trackEnded calls populateQueue if last', () => {
testAction({
action: store.actions.trackEnded,
payload: {test: 'track'},
params: {rootState: {queue: {currentIndex: 1, tracks: [1, 2]}}},
expectedActions: [
{ type: 'radios/populateQueue', payload: null, options: {root: true} },
{ type: 'queue/next', payload: null, options: {root: true} }
]
})
})
it('trackErrored', () => {
testAction({
action: store.actions.trackErrored,
payload: {test: 'track'},
params: {state: {errorCount: 0, maxConsecutiveErrors: 5}},
expectedMutations: [
{ type: 'errored', payload: true },
{ type: 'incrementErrorCount' }
],
expectedActions: [
{ type: 'queue/next', payload: null, options: {root: true} }
]
})
})
it('updateProgress', () => {
testAction({
action: store.actions.updateProgress,
payload: 1,
expectedMutations: [
{ type: 'currentTime', payload: 1 }
]
})
})
it('mute', () => {
testAction({
action: store.actions.mute,
params: {state: { volume: 0.7, tempVolume: 0}},
expectedMutations: [
{ type: 'tempVolume', payload: 0.7 },
{ type: 'volume', payload: 0 },
]
})
})
it('unmute', () => {
testAction({
action: store.actions.unmute,
params: {state: { volume: 0, tempVolume: 0.8}},
expectedMutations: [
{ type: 'volume', payload: 0.8 },
]
})
})
})
})

Wyświetl plik

@ -0,0 +1,37 @@
import {expect} from 'chai'
var sinon = require('sinon')
import moxios from 'moxios'
import store from '@/store/playlists'
import { testAction } from '../../utils'
describe('store/playlists', () => {
var sandbox
beforeEach(function () {
sandbox = sinon.createSandbox()
moxios.install()
})
afterEach(function () {
sandbox.restore()
moxios.uninstall()
})
describe('mutations', () => {
it('set playlists', () => {
const state = { playlists: [] }
store.mutations.playlists(state, [{id: 1, name: 'test'}])
expect(state.playlists).to.deep.equal([{id: 1, name: 'test'}])
})
})
describe('actions', () => {
it('fetchOwn does nothing with no user', () => {
testAction({
action: store.actions.fetchOwn,
payload: null,
params: {state: { playlists: [] }, rootState: {auth: {profile: {}}}},
expectedMutations: []
})
})
})
})

Wyświetl plik

@ -0,0 +1,306 @@
var sinon = require('sinon')
import {expect} from 'chai'
import _ from 'lodash'
import store from '@/store/queue'
import { testAction } from '../../utils'
describe('store/queue', () => {
var sandbox
beforeEach(function () {
// Create a sandbox for the test
sandbox = sinon.createSandbox()
})
afterEach(function () {
// Restore all the things made through the sandbox
sandbox.restore()
})
describe('mutations', () => {
it('currentIndex', () => {
const state = {}
store.mutations.currentIndex(state, 2)
expect(state.currentIndex).to.equal(2)
})
it('ended', () => {
const state = {}
store.mutations.ended(state, false)
expect(state.ended).to.equal(false)
})
it('tracks', () => {
const state = {}
store.mutations.tracks(state, [1, 2])
expect(state.tracks).to.deep.equal([1, 2])
})
it('splice', () => {
const state = {tracks: [1, 2, 3]}
store.mutations.splice(state, {start: 1, size: 2})
expect(state.tracks).to.deep.equal([1])
})
it('insert', () => {
const state = {tracks: [1, 3]}
store.mutations.insert(state, {track: 2, index: 1})
expect(state.tracks).to.deep.equal([1, 2, 3])
})
it('reorder before', () => {
const state = {currentIndex: 3}
store.mutations.reorder(state, {oldIndex: 2, newIndex: 1})
expect(state.currentIndex).to.equal(3)
})
it('reorder from after to before', () => {
const state = {currentIndex: 3}
store.mutations.reorder(state, {oldIndex: 4, newIndex: 1})
expect(state.currentIndex).to.equal(4)
})
it('reorder after', () => {
const state = {currentIndex: 3}
store.mutations.reorder(state, {oldIndex: 4, newIndex: 5})
expect(state.currentIndex).to.equal(3)
})
it('reorder before to after', () => {
const state = {currentIndex: 3}
store.mutations.reorder(state, {oldIndex: 1, newIndex: 5})
expect(state.currentIndex).to.equal(2)
})
it('reorder current', () => {
const state = {currentIndex: 3}
store.mutations.reorder(state, {oldIndex: 3, newIndex: 1})
expect(state.currentIndex).to.equal(1)
})
})
describe('getters', () => {
it('currentTrack', () => {
const state = { tracks: [1, 2, 3], currentIndex: 2 }
expect(store.getters['currentTrack'](state)).to.equal(3)
})
it('hasNext true', () => {
const state = { tracks: [1, 2, 3], currentIndex: 1 }
expect(store.getters['hasNext'](state)).to.equal(true)
})
it('hasNext false', () => {
const state = { tracks: [1, 2, 3], currentIndex: 2 }
expect(store.getters['hasNext'](state)).to.equal(false)
})
})
describe('actions', () => {
it('append at end', () => {
testAction({
action: store.actions.append,
payload: {track: 4},
params: {state: {tracks: [1, 2, 3]}},
expectedMutations: [
{ type: 'insert', payload: {track: 4, index: 3} }
]
})
})
it('append at index', () => {
testAction({
action: store.actions.append,
payload: {track: 2, index: 1},
params: {state: {tracks: [1, 3]}},
expectedMutations: [
{ type: 'insert', payload: {track: 2, index: 1} }
]
})
})
it('appendMany', () => {
const tracks = [{title: 1}, {title: 2}]
testAction({
action: store.actions.appendMany,
payload: {tracks: tracks},
params: {state: {tracks: []}},
expectedActions: [
{ type: 'append', payload: {track: tracks[0], index: 0} },
{ type: 'append', payload: {track: tracks[1], index: 1} },
]
})
})
it('appendMany at index', () => {
const tracks = [{title: 1}, {title: 2}]
testAction({
action: store.actions.appendMany,
payload: {tracks: tracks, index: 1},
params: {state: {tracks: [1, 2]}},
expectedActions: [
{ type: 'append', payload: {track: tracks[0], index: 1} },
{ type: 'append', payload: {track: tracks[1], index: 2} },
]
})
})
it('cleanTrack after current', () => {
testAction({
action: store.actions.cleanTrack,
payload: 3,
params: {state: {currentIndex: 2, tracks: [1, 2, 3, 4, 5]}},
expectedMutations: [
{ type: 'splice', payload: {start: 3, size: 1} }
]
})
})
it('cleanTrack before current', () => {
testAction({
action: store.actions.cleanTrack,
payload: 1,
params: {state: {currentIndex: 2, tracks: []}},
expectedMutations: [
{ type: 'splice', payload: {start: 1, size: 1} },
{ type: 'currentIndex', payload: 1 }
]
})
})
it('cleanTrack current', () => {
testAction({
action: store.actions.cleanTrack,
payload: 2,
params: {state: {currentIndex: 2, tracks: []}},
expectedMutations: [
{ type: 'splice', payload: {start: 2, size: 1} },
{ type: 'currentIndex', payload: 2 }
],
expectedActions: [
{ type: 'player/stop', payload: null, options: {root: true} }
]
})
})
it('cleanTrack current is last', () => {
testAction({
action: store.actions.cleanTrack,
payload: 5,
params: { state: { currentIndex: 5, tracks: [1, 2, 3, 4, 5] } },
expectedMutations: [
{ type: 'splice', payload: { start: 5, size: 1 } },
{ type: 'currentIndex', payload: 4 }
],
expectedActions: [
{ type: 'player/stop', payload: null, options: { root: true } }
]
})
})
it('previous when at beginning', () => {
testAction({
action: store.actions.previous,
params: {state: {currentIndex: 0}},
expectedActions: [
{ type: 'currentIndex', payload: 0 }
]
})
})
it('previous after less than 3 seconds of playback', () => {
testAction({
action: store.actions.previous,
params: {state: {currentIndex: 1}, rootState: {player: {currentTime: 1}}},
expectedActions: [
{ type: 'currentIndex', payload: 0 }
]
})
})
it('previous after more than 3 seconds of playback', () => {
testAction({
action: store.actions.previous,
params: {state: {currentIndex: 1}, rootState: {player: {currentTime: 3}}},
expectedActions: [
{ type: 'currentIndex', payload: 1 }
]
})
})
it('next on last track when looping on queue', () => {
testAction({
action: store.actions.next,
params: {state: {tracks: [1, 2], currentIndex: 1}, rootState: {player: {looping: 2}}},
expectedActions: [
{ type: 'currentIndex', payload: 0 }
]
})
})
it('next track when last track', () => {
testAction({
action: store.actions.next,
params: {state: {tracks: [1, 2], currentIndex: 1}, rootState: {player: {looping: 0}}},
expectedMutations: [
{ type: 'ended', payload: true }
]
})
})
it('next track when not last track', () => {
testAction({
action: store.actions.next,
params: {state: {tracks: [1, 2], currentIndex: 0}, rootState: {player: {looping: 0}}},
expectedActions: [
{ type: 'currentIndex', payload: 1 }
]
})
})
it('currentIndex', () => {
testAction({
action: store.actions.currentIndex,
payload: 1,
params: {state: {tracks: [1, 2], currentIndex: 0}, rootState: {radios: {running: false}}},
expectedMutations: [
{ type: 'ended', payload: false },
{ type: 'player/currentTime', payload: 0, options: {root: true} },
{ type: 'currentIndex', payload: 1 }
]
})
})
it('currentIndex with radio and many tracks remaining', () => {
testAction({
action: store.actions.currentIndex,
payload: 1,
params: {state: {tracks: [1, 2, 3, 4], currentIndex: 0}, rootState: {radios: {running: true}}},
expectedMutations: [
{ type: 'ended', payload: false },
{ type: 'player/currentTime', payload: 0, options: {root: true} },
{ type: 'currentIndex', payload: 1 }
]
})
})
it('currentIndex with radio and less than two tracks remaining', () => {
testAction({
action: store.actions.currentIndex,
payload: 1,
params: {state: {tracks: [1, 2, 3], currentIndex: 0}, rootState: {radios: {running: true}}},
expectedMutations: [
{ type: 'ended', payload: false },
{ type: 'player/currentTime', payload: 0, options: {root: true} },
{ type: 'currentIndex', payload: 1 }
],
expectedActions: [
{ type: 'radios/populateQueue', payload: null, options: {root: true} }
]
})
})
it('clean', () => {
testAction({
action: store.actions.clean,
expectedMutations: [
{ type: 'tracks', payload: [] },
{ type: 'ended', payload: true }
],
expectedActions: [
{ type: 'radios/stop', payload: null, options: {root: true} },
{ type: 'player/stop', payload: null, options: {root: true} },
{ type: 'currentIndex', payload: -1 }
]
})
})
it('shuffle', () => {
let _shuffle = sandbox.stub(_, 'shuffle')
let tracks = ['a', 'b', 'c', 'd', 'e']
let shuffledTracks = ['a', 'b', 'e', 'd', 'c']
_shuffle.returns(shuffledTracks)
testAction({
action: store.actions.shuffle,
params: {state: {currentIndex: 1, tracks: tracks}},
expectedMutations: [
{ type: 'tracks', payload: [] }
],
expectedActions: [
{ type: 'appendMany', payload: {tracks: shuffledTracks} },
{ type: 'currentIndex', payload: {tracks: shuffledTracks} }
]
})
})
})
})

Wyświetl plik

@ -0,0 +1,104 @@
var sinon = require('sinon')
import {expect} from 'chai'
import moxios from 'moxios'
import store from '@/store/radios'
import { testAction } from '../../utils'
describe('store/radios', () => {
var sandbox
beforeEach(function () {
sandbox = sinon.createSandbox()
moxios.install()
})
afterEach(function () {
sandbox.restore()
moxios.uninstall()
})
describe('mutations', () => {
it('current', () => {
const state = {}
store.mutations.current(state, 1)
expect(state.current).to.equal(1)
})
it('running', () => {
const state = {}
store.mutations.running(state, false)
expect(state.running).to.equal(false)
})
})
describe('actions', () => {
it('start', () => {
moxios.stubRequest('radios/sessions/', {
status: 200,
response: {id: 2}
})
testAction({
action: store.actions.start,
payload: {type: 'favorites', objectId: 0, customRadioId: null},
expectedMutations: [
{
type: 'current',
payload: {
type: 'favorites',
objectId: 0,
customRadioId: null,
session: 2
}
},
{ type: 'running', payload: true }
],
expectedActions: [
{ type: 'populateQueue', payload: true }
]
})
})
it('stop', () => {
return testAction({
action: store.actions.stop,
params: {state: {}},
expectedMutations: [
{ type: 'current', payload: null },
{ type: 'running', payload: false }
]
})
})
it('populateQueue', () => {
moxios.stubRequest('radios/tracks/', {
status: 201,
response: {track: {id: 1}}
})
return testAction({
action: store.actions.populateQueue,
params: {
state: {running: true, current: {session: 1}},
rootState: {player: {errorCount: 0, maxConsecutiveErrors: 5}}
},
expectedActions: [
{ type: 'queue/append', payload: {track: {id: 1}}, options: {root: true} }
]
})
})
it('populateQueue does nothing when not running', () => {
testAction({
action: store.actions.populateQueue,
params: {state: {running: false}},
expectedActions: []
})
})
it('populateQueue does nothing when too much errors', () => {
return testAction({
action: store.actions.populateQueue,
payload: {test: 'track'},
params: {
rootState: {player: {errorCount: 5, maxConsecutiveErrors: 5}},
state: {running: true}
},
expectedActions: []
})
})
})
})

Wyświetl plik

@ -0,0 +1,32 @@
import {expect} from 'chai'
import {parseAPIErrors} from '@/utils'
describe('utils', () => {
describe('parseAPIErrors', () => {
it('handles flat structure', () => {
const input = {"old_password": ["Invalid password"]}
let expected = ["Invalid password"]
let output = parseAPIErrors(input)
expect(output).to.deep.equal(expected)
})
it('handles flat structure with multiple errors per field', () => {
const input = {"old_password": ["Invalid password", "Too short"]}
let expected = ["Invalid password", "Too short"]
let output = parseAPIErrors(input)
expect(output).to.deep.equal(expected)
})
it('translate field name', () => {
const input = {"old_password": ["This field is required"]}
let expected = ["Old Password: This field is required"]
let output = parseAPIErrors(input)
expect(output).to.deep.equal(expected)
})
it('handle nested fields', () => {
const input = {"summary": {"text": ["Ensure this field has no more than 5000 characters."]}}
let expected = ["Summary - Text: Ensure this field has no more than 5000 characters."]
let output = parseAPIErrors(input)
expect(output).to.deep.equal(expected)
})
})
})

Wyświetl plik

@ -0,0 +1,64 @@
const sinon = require('sinon')
import { expect } from 'chai'
import { shallowMount, createLocalVue, RouterLinkStub } from '@vue/test-utils'
import AlbumDetail from '@/views/admin/library/AlbumDetail.vue'
import GetTextPlugin from 'vue-gettext'
import HumanDate from '@/components/common/HumanDate.vue'
import DangerousButton from '@/components/common/DangerousButton.vue'
describe('views/admin/library', () => {
let wrapper
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
})
afterEach(() => {
sandbox.restore()
})
describe('Album details', () => {
it('displays default cover', async () => {
const album = { cover: null, artist: { id: 1 }, title: "dummy", id: 1, creation_date: "2020-01-01" }
const localVue = createLocalVue()
localVue.directive('title', (() => null))
localVue.directive('dropdown', (() => null))
localVue.use(GetTextPlugin, { translations: {} })
localVue.filter('truncate', () => null)
localVue.filter('humanSize', () => null)
localVue.filter('ago', () => null)
localVue.filter('moment', () => null)
// overrides axios calls
sandbox.stub(AlbumDetail.methods, "fetchData").callsFake(() => null)
sandbox.stub(AlbumDetail.methods, "fetchStats").callsFake(() => null)
wrapper = shallowMount(AlbumDetail, {
localVue,
data() {
return {
isLoading: false,
isLoadingStats: false,
object: album,
stats: [],
}
},
mocks: {
$store: {
state: { auth: { profile: null }, ui: { lastDate: null } }
},
},
stubs: {
'human-date': HumanDate,
'dangerous-button': DangerousButton,
'router-link': RouterLinkStub
},
propsData: {
id: 1
},
computed: { labels: () => { return { statsWarning: null } } }
})
expect(wrapper.find('img').attributes('src')).to.include("default-cover")
})
})
})

Wyświetl plik

@ -0,0 +1,77 @@
// helper for testing action with expected mutations
import Vue from 'vue'
import {expect} from 'chai'
export const render = (Component, propsData) => {
const Constructor = Vue.extend(Component)
return new Constructor({ propsData: propsData }).$mount()
}
export const testAction = ({action, payload, params, expectedMutations, expectedActions}, done) => {
let mutationsCount = 0
let actionsCount = 0
if (!expectedMutations) {
expectedMutations = []
}
if (!expectedActions) {
expectedActions = []
}
const isOver = () => {
return mutationsCount >= expectedMutations.length && actionsCount >= expectedActions.length
}
// mock commit
const commit = (type, payload) => {
const mutation = expectedMutations[mutationsCount]
expect(mutation.type).to.equal(type)
if (payload) {
expect(mutation.payload).to.deep.equal(payload)
}
mutationsCount++
if (isOver()) {
return
}
}
// mock dispatch
const dispatch = (type, payload, options) => {
const a = expectedActions[actionsCount]
if (!a) {
throw Error(`Unexecpted action ${type}`)
}
expect(a.type).to.equal(type)
if (payload) {
expect(a.payload).to.deep.equal(payload)
}
if (a.options) {
expect(options).to.deep.equal(a.options)
}
actionsCount++
if (isOver()) {
return
}
}
let end = function () {
// check if no mutations should have been dispatched
if (expectedMutations.length === 0) {
expect(mutationsCount).to.equal(0)
}
if (expectedActions.length === 0) {
expect(actionsCount).to.equal(0)
}
if (isOver()) {
return
}
}
// call the action with mocked store and arguments
let promise = action({ commit, dispatch, ...params }, payload)
if (promise) {
promise.then(end)
return promise
} else {
return end()
}
}