Merge branch 'feature/frontend-unittests' into 'develop'
Feature/frontend unittests See merge request funkwhale/funkwhale!40
This commit is contained in:
commit
e0820dfa1c
|
@ -2,7 +2,7 @@ variables:
|
|||
IMAGE_NAME: funkwhale/funkwhale
|
||||
IMAGE: $IMAGE_NAME:$CI_COMMIT_REF_NAME
|
||||
IMAGE_LATEST: $IMAGE_NAME:latest
|
||||
|
||||
PIP_CACHE_DIR: "$CI_PROJECT_DIR/pip-cache"
|
||||
|
||||
|
||||
stages:
|
||||
|
@ -14,40 +14,61 @@ test_api:
|
|||
services:
|
||||
- postgres:9.4
|
||||
stage: test
|
||||
image: funkwhale/funkwhale:base
|
||||
image: funkwhale/funkwhale:latest
|
||||
cache:
|
||||
key: "$CI_PROJECT_ID/pip_cache"
|
||||
paths:
|
||||
- "$PIP_CACHE_DIR"
|
||||
variables:
|
||||
PIP_CACHE_DIR: "$CI_PROJECT_DIR/pip-cache"
|
||||
DATABASE_URL: "postgresql://postgres@postgres/postgres"
|
||||
|
||||
before_script:
|
||||
- python3 -m venv --copies virtualenv
|
||||
- source virtualenv/bin/activate
|
||||
- cd api
|
||||
- pip install -r requirements/base.txt
|
||||
- pip install -r requirements/local.txt
|
||||
- pip install -r requirements/test.txt
|
||||
script:
|
||||
- pytest
|
||||
cache:
|
||||
key: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
|
||||
paths:
|
||||
- "$CI_PROJECT_DIR/pip-cache"
|
||||
tags:
|
||||
- docker
|
||||
|
||||
build_front:
|
||||
stage: build
|
||||
image: node:6-alpine
|
||||
|
||||
test_front:
|
||||
stage: test
|
||||
image: node:9
|
||||
before_script:
|
||||
- cd front
|
||||
|
||||
script:
|
||||
- npm install
|
||||
- npm run build
|
||||
- yarn install
|
||||
- yarn run unit
|
||||
cache:
|
||||
key: "$CI_COMMIT_REF_NAME"
|
||||
key: "$CI_PROJECT_ID/front_dependencies"
|
||||
paths:
|
||||
- front/node_modules
|
||||
- front/yarn.lock
|
||||
artifacts:
|
||||
name: "front_${CI_COMMIT_REF_NAME}"
|
||||
paths:
|
||||
- front/dist/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
|
||||
build_front:
|
||||
stage: build
|
||||
image: node:9
|
||||
before_script:
|
||||
- cd front
|
||||
|
||||
script:
|
||||
- yarn install
|
||||
- yarn run build
|
||||
cache:
|
||||
key: "$CI_PROJECT_ID/front_dependencies"
|
||||
paths:
|
||||
- front/node_modules
|
||||
- front/yarn.lock
|
||||
artifacts:
|
||||
name: "front_${CI_COMMIT_REF_NAME}"
|
||||
paths:
|
||||
|
|
|
@ -43,7 +43,7 @@ class TrackFavoriteViewSet(mixins.CreateModelMixin,
|
|||
favorite = models.TrackFavorite.add(track=track, user=self.request.user)
|
||||
return favorite
|
||||
|
||||
@list_route(methods=['delete'])
|
||||
@list_route(methods=['delete', 'post'])
|
||||
def remove(self, request, *args, **kwargs):
|
||||
try:
|
||||
pk = int(request.data['track'])
|
||||
|
|
|
@ -4,7 +4,7 @@ Populates the database with fake data
|
|||
import random
|
||||
|
||||
from funkwhale_api.music import models
|
||||
from funkwhale_api.music.tests import factories
|
||||
from funkwhale_api.music import factories
|
||||
|
||||
|
||||
def create_data(count=25):
|
||||
|
@ -19,4 +19,4 @@ def create_data(count=25):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
create_data()
|
||||
|
|
|
@ -47,8 +47,7 @@ mutagen>=1.39,<1.40
|
|||
|
||||
|
||||
# Until this is merged
|
||||
#django-taggit>=0.22,<0.23
|
||||
git+https://github.com/alex/django-taggit.git@95776ac66948ed7ba7c12e35c1170551e3be66a5
|
||||
django-taggit>=0.22,<0.23
|
||||
# Until this is merged
|
||||
git+https://github.com/EliotBerriot/PyMemoize.git@django
|
||||
# Until this is merged
|
||||
|
|
|
@ -58,11 +58,14 @@ def test_user_can_remove_favorite_via_api(logged_in_client, factories, client):
|
|||
assert response.status_code == 204
|
||||
assert TrackFavorite.objects.count() == 0
|
||||
|
||||
def test_user_can_remove_favorite_via_api_using_track_id(factories, logged_in_client):
|
||||
|
||||
@pytest.mark.parametrize('method', ['delete', 'post'])
|
||||
def test_user_can_remove_favorite_via_api_using_track_id(
|
||||
method, factories, logged_in_client):
|
||||
favorite = factories['favorites.TrackFavorite'](user=logged_in_client.user)
|
||||
|
||||
url = reverse('api:v1:favorites:tracks-remove')
|
||||
response = logged_in_client.delete(
|
||||
response = getattr(logged_in_client, method)(
|
||||
url, json.dumps({'track': favorite.track.pk}),
|
||||
content_type='application/json'
|
||||
)
|
||||
|
|
4
dev.yml
4
dev.yml
|
@ -3,9 +3,7 @@ version: '2'
|
|||
services:
|
||||
|
||||
front:
|
||||
build:
|
||||
dockerfile: docker/Dockerfile.dev
|
||||
context: ./front
|
||||
build: front
|
||||
env_file: .env.dev
|
||||
environment:
|
||||
- "HOST=0.0.0.0"
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
FROM node:6-alpine
|
||||
FROM node:9
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
WORKDIR /app/
|
||||
ADD package.json .
|
||||
RUN yarn install --only=production
|
||||
RUN yarn install --only=dev
|
||||
VOLUME ["/app/node_modules"]
|
||||
COPY . .
|
||||
|
||||
RUN npm install
|
||||
|
||||
ADD . .
|
||||
|
||||
RUN npm run build
|
||||
CMD ["npm", "run", "dev"]
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
FROM node:6-alpine
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
ADD package.json .
|
||||
|
||||
RUN npm install
|
||||
|
||||
VOLUME ["/app/node_modules"]
|
||||
|
||||
CMD ["npm", "run", "dev"]
|
|
@ -9,19 +9,21 @@
|
|||
"start": "node build/dev-server.js",
|
||||
"build": "node build/build.js",
|
||||
"unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
|
||||
"unit-watch": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js",
|
||||
"e2e": "node test/e2e/runner.js",
|
||||
"test": "npm run unit && npm run e2e",
|
||||
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.17.1",
|
||||
"dateformat": "^2.0.0",
|
||||
"js-logger": "^1.3.0",
|
||||
"jwt-decode": "^2.2.0",
|
||||
"lodash": "^4.17.4",
|
||||
"moxios": "^0.4.0",
|
||||
"semantic-ui-css": "^2.2.10",
|
||||
"vue": "^2.3.3",
|
||||
"vue-lazyload": "^1.1.4",
|
||||
"vue-resource": "^1.3.4",
|
||||
"vue-router": "^2.3.1",
|
||||
"vue-upload-component": "^2.7.4",
|
||||
"vuedraggable": "^2.14.1",
|
||||
|
@ -46,6 +48,7 @@
|
|||
"cross-env": "^4.0.0",
|
||||
"cross-spawn": "^5.0.1",
|
||||
"css-loader": "^0.28.0",
|
||||
"es6-promise": "^4.2.2",
|
||||
"eslint": "^3.19.0",
|
||||
"eslint-config-standard": "^6.2.1",
|
||||
"eslint-friendly-formatter": "^2.0.7",
|
||||
|
@ -67,6 +70,7 @@
|
|||
"karma-phantomjs-launcher": "^1.0.2",
|
||||
"karma-phantomjs-shim": "^1.4.0",
|
||||
"karma-sinon-chai": "^1.3.1",
|
||||
"karma-sinon-stub-promise": "^1.0.0",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-spec-reporter": "0.0.30",
|
||||
"karma-webpack": "^2.0.2",
|
||||
|
@ -85,6 +89,7 @@
|
|||
"shelljs": "^0.7.6",
|
||||
"sinon": "^2.1.0",
|
||||
"sinon-chai": "^2.8.0",
|
||||
"sinon-stub-promise": "^4.0.0",
|
||||
"url-loader": "^0.5.8",
|
||||
"vue-loader": "^12.1.0",
|
||||
"vue-style-loader": "^3.0.1",
|
||||
|
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
|
@ -29,13 +29,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import backend from '@/audio/backend'
|
||||
import AlbumCard from '@/components/audio/album/Card'
|
||||
import ArtistCard from '@/components/audio/artist/Card'
|
||||
import config from '@/config'
|
||||
|
||||
const SEARCH_URL = config.API_URL + 'search'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -73,17 +71,8 @@ export default {
|
|||
let params = {
|
||||
query: this.query
|
||||
}
|
||||
this.$http.get(SEARCH_URL, {
|
||||
params: params,
|
||||
before (request) {
|
||||
// abort previous request, if exists
|
||||
if (this.previousRequest) {
|
||||
this.previousRequest.abort()
|
||||
}
|
||||
|
||||
// set previous request on Vue instance
|
||||
this.previousRequest = request
|
||||
}
|
||||
axios.get('search', {
|
||||
params: params
|
||||
}).then((response) => {
|
||||
self.results = self.castResults(response.data)
|
||||
self.isLoading = false
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import axios from 'axios'
|
||||
import config from '@/config'
|
||||
import logger from '@/logging'
|
||||
|
||||
|
@ -61,8 +61,8 @@ export default {
|
|||
new_password1: this.new_password,
|
||||
new_password2: this.new_password
|
||||
}
|
||||
let resource = Vue.resource(config.BACKEND_URL + 'api/auth/registration/change-password/')
|
||||
return resource.save({}, credentials).then(response => {
|
||||
let url = config.BACKEND_URL + 'api/auth/registration/change-password/'
|
||||
return axios.post(url, credentials).then(response => {
|
||||
logger.default.info('Password successfully changed')
|
||||
self.$router.push('/profile/me')
|
||||
}, response => {
|
||||
|
|
|
@ -54,15 +54,15 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import $ from 'jquery'
|
||||
import logger from '@/logging'
|
||||
import config from '@/config'
|
||||
import TrackTable from '@/components/audio/track/Table'
|
||||
import RadioButton from '@/components/radios/Button'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import OrderingMixin from '@/components/mixins/Ordering'
|
||||
import PaginationMixin from '@/components/mixins/Pagination'
|
||||
const FAVORITES_URL = config.API_URL + 'tracks/'
|
||||
const FAVORITES_URL = 'tracks/'
|
||||
|
||||
export default {
|
||||
mixins: [OrderingMixin, PaginationMixin],
|
||||
|
@ -115,7 +115,7 @@ export default {
|
|||
ordering: this.getOrderingAsString()
|
||||
}
|
||||
logger.default.time('Loading user favorites')
|
||||
this.$http.get(url, {params: params}).then((response) => {
|
||||
axios.get(url, {params: params}).then((response) => {
|
||||
self.results = response.data
|
||||
self.nextLink = response.data.next
|
||||
self.previousLink = response.data.previous
|
||||
|
|
|
@ -41,14 +41,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import backend from '@/audio/backend'
|
||||
import PlayButton from '@/components/audio/PlayButton'
|
||||
import TrackTable from '@/components/audio/track/Table'
|
||||
import config from '@/config'
|
||||
|
||||
const FETCH_URL = config.API_URL + 'albums/'
|
||||
const FETCH_URL = 'albums/'
|
||||
|
||||
export default {
|
||||
props: ['id'],
|
||||
|
@ -71,7 +70,7 @@ export default {
|
|||
this.isLoading = true
|
||||
let url = FETCH_URL + this.id + '/'
|
||||
logger.default.debug('Fetching album "' + this.id + '"')
|
||||
this.$http.get(url).then((response) => {
|
||||
axios.get(url).then((response) => {
|
||||
self.album = backend.Album.clean(response.data)
|
||||
self.isLoading = false
|
||||
})
|
||||
|
|
|
@ -41,15 +41,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import backend from '@/audio/backend'
|
||||
import AlbumCard from '@/components/audio/album/Card'
|
||||
import RadioButton from '@/components/radios/Button'
|
||||
import PlayButton from '@/components/audio/PlayButton'
|
||||
import config from '@/config'
|
||||
|
||||
const FETCH_URL = config.API_URL + 'artists/'
|
||||
const FETCH_URL = 'artists/'
|
||||
|
||||
export default {
|
||||
props: ['id'],
|
||||
|
@ -74,7 +73,7 @@ export default {
|
|||
this.isLoading = true
|
||||
let url = FETCH_URL + this.id + '/'
|
||||
logger.default.debug('Fetching artist "' + this.id + '"')
|
||||
this.$http.get(url).then((response) => {
|
||||
axios.get(url).then((response) => {
|
||||
self.artist = response.data
|
||||
self.albums = JSON.parse(JSON.stringify(self.artist.albums)).map((album) => {
|
||||
return backend.Album.clean(album)
|
||||
|
|
|
@ -57,10 +57,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import _ from 'lodash'
|
||||
import $ from 'jquery'
|
||||
|
||||
import config from '@/config'
|
||||
import backend from '@/audio/backend'
|
||||
import logger from '@/logging'
|
||||
|
||||
|
@ -69,7 +69,7 @@ import PaginationMixin from '@/components/mixins/Pagination'
|
|||
import ArtistCard from '@/components/audio/artist/Card'
|
||||
import Pagination from '@/components/Pagination'
|
||||
|
||||
const FETCH_URL = config.API_URL + 'artists/'
|
||||
const FETCH_URL = 'artists/'
|
||||
|
||||
export default {
|
||||
mixins: [OrderingMixin, PaginationMixin],
|
||||
|
@ -124,7 +124,7 @@ export default {
|
|||
ordering: this.getOrderingAsString()
|
||||
}
|
||||
logger.default.debug('Fetching artists')
|
||||
this.$http.get(url, {params: params}).then((response) => {
|
||||
axios.get(url, {params: params}).then((response) => {
|
||||
self.result = response.data
|
||||
self.result.results.map((artist) => {
|
||||
var albums = JSON.parse(JSON.stringify(artist.albums)).map((album) => {
|
||||
|
|
|
@ -24,14 +24,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import Search from '@/components/audio/Search'
|
||||
import backend from '@/audio/backend'
|
||||
import logger from '@/logging'
|
||||
import ArtistCard from '@/components/audio/artist/Card'
|
||||
import config from '@/config'
|
||||
import RadioCard from '@/components/radios/Card'
|
||||
|
||||
const ARTISTS_URL = config.API_URL + 'artists/'
|
||||
const ARTISTS_URL = 'artists/'
|
||||
|
||||
export default {
|
||||
name: 'library',
|
||||
|
@ -58,7 +58,7 @@ export default {
|
|||
}
|
||||
let url = ARTISTS_URL
|
||||
logger.default.time('Loading latest artists')
|
||||
this.$http.get(url, {params: params}).then((response) => {
|
||||
axios.get(url, {params: params}).then((response) => {
|
||||
self.artists = response.data.results
|
||||
self.artists.map((artist) => {
|
||||
var albums = JSON.parse(JSON.stringify(artist.albums)).map((album) => {
|
||||
|
|
|
@ -59,10 +59,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import _ from 'lodash'
|
||||
import $ from 'jquery'
|
||||
|
||||
import config from '@/config'
|
||||
import logger from '@/logging'
|
||||
|
||||
import OrderingMixin from '@/components/mixins/Ordering'
|
||||
|
@ -70,7 +70,7 @@ import PaginationMixin from '@/components/mixins/Pagination'
|
|||
import RadioCard from '@/components/radios/Card'
|
||||
import Pagination from '@/components/Pagination'
|
||||
|
||||
const FETCH_URL = config.API_URL + 'radios/radios/'
|
||||
const FETCH_URL = 'radios/radios/'
|
||||
|
||||
export default {
|
||||
mixins: [OrderingMixin, PaginationMixin],
|
||||
|
@ -125,7 +125,7 @@ export default {
|
|||
ordering: this.getOrderingAsString()
|
||||
}
|
||||
logger.default.debug('Fetching radios')
|
||||
this.$http.get(url, {params: params}).then((response) => {
|
||||
axios.get(url, {params: params}).then((response) => {
|
||||
self.result = response.data
|
||||
self.isLoading = false
|
||||
})
|
||||
|
|
|
@ -60,15 +60,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
import url from '@/utils/url'
|
||||
import logger from '@/logging'
|
||||
import backend from '@/audio/backend'
|
||||
import PlayButton from '@/components/audio/PlayButton'
|
||||
import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
|
||||
import config from '@/config'
|
||||
|
||||
const FETCH_URL = config.API_URL + 'tracks/'
|
||||
const FETCH_URL = 'tracks/'
|
||||
|
||||
export default {
|
||||
props: ['id'],
|
||||
|
@ -94,7 +93,7 @@ export default {
|
|||
this.isLoadingTrack = true
|
||||
let url = FETCH_URL + this.id + '/'
|
||||
logger.default.debug('Fetching track "' + this.id + '"')
|
||||
this.$http.get(url).then((response) => {
|
||||
axios.get(url).then((response) => {
|
||||
self.track = response.data
|
||||
self.isLoadingTrack = false
|
||||
})
|
||||
|
@ -104,7 +103,7 @@ export default {
|
|||
this.isLoadingLyrics = true
|
||||
let url = FETCH_URL + this.id + '/lyrics/'
|
||||
logger.default.debug('Fetching lyrics for track "' + this.id + '"')
|
||||
this.$http.get(url).then((response) => {
|
||||
axios.get(url).then((response) => {
|
||||
self.lyrics = response.data
|
||||
self.isLoadingLyrics = false
|
||||
}, (response) => {
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import config from '@/config'
|
||||
|
||||
import ImportMixin from './ImportMixin'
|
||||
import ReleaseImport from './ReleaseImport'
|
||||
|
@ -92,9 +92,8 @@ export default Vue.extend({
|
|||
fetchReleaseGroupsData () {
|
||||
let self = this
|
||||
this.releaseGroups.forEach(group => {
|
||||
let url = config.API_URL + 'providers/musicbrainz/releases/browse/' + group.id + '/'
|
||||
let resource = Vue.resource(url)
|
||||
resource.get({}).then((response) => {
|
||||
let url = 'providers/musicbrainz/releases/browse/' + group.id + '/'
|
||||
return axios.get(url).then((response) => {
|
||||
logger.default.info('successfully fetched release group', group.id)
|
||||
let release = response.data['release-list'].filter(r => {
|
||||
return r.status === 'Official'
|
||||
|
|
|
@ -52,11 +52,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import config from '@/config'
|
||||
|
||||
const FETCH_URL = config.API_URL + 'import-batches/'
|
||||
const FETCH_URL = 'import-batches/'
|
||||
|
||||
export default {
|
||||
props: ['id'],
|
||||
|
@ -75,7 +74,7 @@ export default {
|
|||
this.isLoading = true
|
||||
let url = FETCH_URL + this.id + '/'
|
||||
logger.default.debug('Fetching batch "' + this.id + '"')
|
||||
this.$http.get(url).then((response) => {
|
||||
axios.get(url).then((response) => {
|
||||
self.batch = response.data
|
||||
self.isLoading = false
|
||||
if (self.batch.status === 'pending') {
|
||||
|
|
|
@ -42,10 +42,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import config from '@/config'
|
||||
|
||||
const BATCHES_URL = config.API_URL + 'import-batches/'
|
||||
const BATCHES_URL = 'import-batches/'
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
|
@ -65,7 +65,7 @@ export default {
|
|||
var self = this
|
||||
this.isLoading = true
|
||||
logger.default.time('Loading import batches')
|
||||
this.$http.get(url, {}).then((response) => {
|
||||
axios.get(url, {}).then((response) => {
|
||||
self.results = response.data.results
|
||||
self.nextLink = response.data.next
|
||||
self.previousLink = response.data.previous
|
||||
|
|
|
@ -62,10 +62,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import FileUploadWidget from './FileUploadWidget'
|
||||
import config from '@/config'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -74,7 +73,7 @@ export default {
|
|||
data () {
|
||||
return {
|
||||
files: [],
|
||||
uploadUrl: config.API_URL + 'import-jobs/',
|
||||
uploadUrl: 'import-jobs/',
|
||||
batch: null
|
||||
}
|
||||
},
|
||||
|
@ -106,9 +105,7 @@ export default {
|
|||
},
|
||||
createBatch () {
|
||||
let self = this
|
||||
let url = config.API_URL + 'import-batches/'
|
||||
let resource = Vue.resource(url)
|
||||
resource.save({}, {}).then((response) => {
|
||||
return axios.post('import-batches/', {}).then((response) => {
|
||||
self.batch = response.data
|
||||
}, (response) => {
|
||||
logger.default.error('error while launching creating batch')
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import config from '@/config'
|
||||
import Vue from 'vue'
|
||||
import router from '@/router'
|
||||
|
||||
export default {
|
||||
|
@ -31,10 +30,9 @@ export default {
|
|||
launchImport () {
|
||||
let self = this
|
||||
this.isImporting = true
|
||||
let url = config.API_URL + 'submit/' + self.importType + '/'
|
||||
let url = 'submit/' + self.importType + '/'
|
||||
let payload = self.importData
|
||||
let resource = Vue.resource(url)
|
||||
resource.save({}, payload).then((response) => {
|
||||
axios.post(url, payload).then((response) => {
|
||||
logger.default.info('launched import for', self.type, self.metadata.id)
|
||||
self.isImporting = false
|
||||
router.push({
|
||||
|
|
|
@ -70,9 +70,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import Vue from 'vue'
|
||||
import time from '@/utils/time'
|
||||
import config from '@/config'
|
||||
import logger from '@/logging'
|
||||
import ImportMixin from './ImportMixin'
|
||||
|
||||
|
@ -117,10 +117,8 @@ export default Vue.extend({
|
|||
search () {
|
||||
let self = this
|
||||
this.isLoading = true
|
||||
let url = config.API_URL + 'providers/' + this.currentBackendId + '/search/'
|
||||
let resource = Vue.resource(url)
|
||||
|
||||
resource.get({query: this.query}).then((response) => {
|
||||
let url = 'providers/' + this.currentBackendId + '/search/'
|
||||
axios.get(url, {params: {query: this.query}}).then((response) => {
|
||||
logger.default.debug('searching', self.query, 'on', self.currentBackendId)
|
||||
self.results = response.data
|
||||
self.isLoading = false
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import config from '@/config'
|
||||
import axios from 'axios'
|
||||
import $ from 'jquery'
|
||||
import _ from 'lodash'
|
||||
import BuilderFilter from './Filter'
|
||||
|
@ -107,8 +107,8 @@ export default {
|
|||
methods: {
|
||||
fetchFilters: function () {
|
||||
let self = this
|
||||
let url = config.API_URL + 'radios/radios/filters/'
|
||||
return this.$http.get(url).then((response) => {
|
||||
let url = 'radios/radios/filters/'
|
||||
return axios.get(url).then((response) => {
|
||||
self.availableFilters = response.data
|
||||
})
|
||||
},
|
||||
|
@ -130,8 +130,8 @@ export default {
|
|||
},
|
||||
fetch: function () {
|
||||
let self = this
|
||||
let url = config.API_URL + 'radios/radios/' + this.id + '/'
|
||||
this.$http.get(url).then((response) => {
|
||||
let url = 'radios/radios/' + this.id + '/'
|
||||
axios.get(url).then((response) => {
|
||||
self.filters = response.data.config.map(f => {
|
||||
return {
|
||||
config: f,
|
||||
|
@ -145,7 +145,7 @@ export default {
|
|||
},
|
||||
fetchCandidates: function () {
|
||||
let self = this
|
||||
let url = config.API_URL + 'radios/radios/validate/'
|
||||
let url = 'radios/radios/validate/'
|
||||
let final = this.filters.map(f => {
|
||||
let c = _.clone(f.config)
|
||||
c.type = f.filter.type
|
||||
|
@ -156,7 +156,7 @@ export default {
|
|||
{'type': 'group', filters: final}
|
||||
]
|
||||
}
|
||||
this.$http.post(url, final).then((response) => {
|
||||
axios.post(url, final).then((response) => {
|
||||
self.checkResult = response.data.filters[0]
|
||||
})
|
||||
},
|
||||
|
@ -173,12 +173,12 @@ export default {
|
|||
'config': final
|
||||
}
|
||||
if (this.id) {
|
||||
let url = config.API_URL + 'radios/radios/' + this.id + '/'
|
||||
this.$http.put(url, final).then((response) => {
|
||||
let url = 'radios/radios/' + this.id + '/'
|
||||
axios.put(url, final).then((response) => {
|
||||
})
|
||||
} else {
|
||||
let url = config.API_URL + 'radios/radios/'
|
||||
this.$http.post(url, final).then((response) => {
|
||||
let url = 'radios/radios/'
|
||||
axios.post(url, final).then((response) => {
|
||||
self.$router.push({
|
||||
name: 'library.radios.edit',
|
||||
params: {
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
</tr>
|
||||
</template>
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import config from '@/config'
|
||||
import $ from 'jquery'
|
||||
import _ from 'lodash'
|
||||
|
@ -132,11 +133,11 @@ export default {
|
|||
methods: {
|
||||
fetchCandidates: function () {
|
||||
let self = this
|
||||
let url = config.API_URL + 'radios/radios/validate/'
|
||||
let url = 'radios/radios/validate/'
|
||||
let final = _.clone(this.config)
|
||||
final.type = this.filter.type
|
||||
final = {'filters': [final]}
|
||||
this.$http.post(url, final).then((response) => {
|
||||
axios.post(url, final).then((response) => {
|
||||
self.checkResult = response.data.filters[0]
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,11 +3,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
|
||||
import config from '@/config'
|
||||
import Vue from 'vue'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
mbId: {type: String, required: true}
|
||||
|
@ -25,9 +23,8 @@ export default {
|
|||
fetchData () {
|
||||
let self = this
|
||||
this.isLoading = true
|
||||
let url = config.API_URL + 'providers/musicbrainz/' + this.type + 's/' + this.mbId + '/'
|
||||
let resource = Vue.resource(url)
|
||||
resource.get({}).then((response) => {
|
||||
let url = 'providers/musicbrainz/' + this.type + 's/' + this.mbId + '/'
|
||||
axios.get(url).then((response) => {
|
||||
logger.default.info('successfully fetched', self.type, self.mbId)
|
||||
self.data = response.data[self.type]
|
||||
this.$emit('metadata-changed', self.data)
|
||||
|
|
|
@ -4,7 +4,7 @@ class Config {
|
|||
if (this.BACKEND_URL === '/') {
|
||||
this.BACKEND_URL = window.location.protocol + '//' + window.location.hostname + ':' + window.location.port
|
||||
}
|
||||
if (!this.BACKEND_URL.endsWith('/')) {
|
||||
if (this.BACKEND_URL.slice(-1) !== '/') {
|
||||
this.BACKEND_URL += '/'
|
||||
}
|
||||
this.API_URL = this.BACKEND_URL + 'api/v1/'
|
||||
|
|
|
@ -8,9 +8,10 @@ logger.default.debug('Environment variables:', process.env)
|
|||
import Vue from 'vue'
|
||||
import App from './App'
|
||||
import router from './router'
|
||||
import VueResource from 'vue-resource'
|
||||
import axios from 'axios'
|
||||
import VueLazyload from 'vue-lazyload'
|
||||
import store from './store'
|
||||
import config from './config'
|
||||
|
||||
window.$ = window.jQuery = require('jquery')
|
||||
|
||||
|
@ -19,25 +20,33 @@ window.$ = window.jQuery = require('jquery')
|
|||
// require('./semantic/semantic.css')
|
||||
require('semantic-ui-css/semantic.js')
|
||||
|
||||
Vue.use(VueResource)
|
||||
Vue.use(VueLazyload)
|
||||
Vue.config.productionTip = false
|
||||
|
||||
Vue.http.interceptors.push(function (request, next) {
|
||||
// modify headers
|
||||
axios.defaults.baseURL = config.API_URL
|
||||
axios.interceptors.request.use(function (config) {
|
||||
// Do something before request is sent
|
||||
if (store.state.auth.authenticated) {
|
||||
request.headers.set('Authorization', store.getters['auth/header'])
|
||||
config.headers['Authorization'] = store.getters['auth/header']
|
||||
}
|
||||
next(function (response) {
|
||||
// redirect to login form when we get unauthorized response from server
|
||||
if (response.status === 401) {
|
||||
store.commit('auth/authenticated', false)
|
||||
logger.default.warn('Received 401 response from API, redirecting to login form')
|
||||
router.push({name: 'login', query: {next: router.currentRoute.fullPath}})
|
||||
}
|
||||
})
|
||||
return config
|
||||
}, function (error) {
|
||||
// Do something with request error
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
// Add a response interceptor
|
||||
axios.interceptors.response.use(function (response) {
|
||||
if (response.status === 401) {
|
||||
store.commit('auth/authenticated', false)
|
||||
logger.default.warn('Received 401 response from API, redirecting to login form')
|
||||
router.push({name: 'login', query: {next: router.currentRoute.fullPath}})
|
||||
}
|
||||
return response
|
||||
}, function (error) {
|
||||
// Do something with response error
|
||||
return Promise.reject(error)
|
||||
})
|
||||
store.dispatch('auth/check')
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
import Vue from 'vue'
|
||||
import axios from 'axios'
|
||||
import jwtDecode from 'jwt-decode'
|
||||
import config from '@/config'
|
||||
import logger from '@/logging'
|
||||
import router from '@/router'
|
||||
|
||||
const LOGIN_URL = config.API_URL + 'token/'
|
||||
const REFRESH_TOKEN_URL = config.API_URL + 'token/refresh/'
|
||||
const USER_PROFILE_URL = config.API_URL + 'users/users/me/'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
|
@ -54,9 +49,8 @@ export default {
|
|||
},
|
||||
actions: {
|
||||
// Send a request to the login URL and save the returned JWT
|
||||
login ({commit, dispatch, state}, {next, credentials, onError}) {
|
||||
let resource = Vue.resource(LOGIN_URL)
|
||||
return resource.save({}, credentials).then(response => {
|
||||
login ({commit, dispatch}, {next, credentials, onError}) {
|
||||
return axios.post('token/', credentials).then(response => {
|
||||
logger.default.info('Successfully logged in as', credentials.username)
|
||||
commit('token', response.data.token)
|
||||
commit('username', credentials.username)
|
||||
|
@ -91,8 +85,7 @@ export default {
|
|||
}
|
||||
},
|
||||
fetchProfile ({commit, dispatch, state}) {
|
||||
let resource = Vue.resource(USER_PROFILE_URL)
|
||||
return resource.get({}).then((response) => {
|
||||
return axios.get('users/users/me/').then((response) => {
|
||||
logger.default.info('Successfully fetched user profile')
|
||||
let data = response.data
|
||||
commit('profile', data)
|
||||
|
@ -107,8 +100,7 @@ export default {
|
|||
})
|
||||
},
|
||||
refreshToken ({commit, dispatch, state}) {
|
||||
let resource = Vue.resource(REFRESH_TOKEN_URL)
|
||||
return resource.save({}, {token: state.token}).then(response => {
|
||||
return axios.post('token/refresh/', {token: state.token}).then(response => {
|
||||
logger.default.info('Refreshed auth token')
|
||||
commit('token', response.data.token)
|
||||
}, response => {
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import Vue from 'vue'
|
||||
import config from '@/config'
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
|
||||
const REMOVE_URL = config.API_URL + 'favorites/tracks/remove/'
|
||||
const FAVORITES_URL = config.API_URL + 'favorites/tracks/'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
|
@ -35,16 +31,14 @@ export default {
|
|||
set ({commit, state}, {id, value}) {
|
||||
commit('track', {id, value})
|
||||
if (value) {
|
||||
let resource = Vue.resource(FAVORITES_URL)
|
||||
resource.save({}, {'track': id}).then((response) => {
|
||||
return axios.post('favorites/tracks/', {'track': id}).then((response) => {
|
||||
logger.default.info('Successfully added track to favorites')
|
||||
}, (response) => {
|
||||
logger.default.info('Error while adding track to favorites')
|
||||
commit('track', {id, value: !value})
|
||||
})
|
||||
} else {
|
||||
let resource = Vue.resource(REMOVE_URL)
|
||||
resource.delete({}, {'track': id}).then((response) => {
|
||||
return axios.post('favorites/tracks/remove/', {'track': id}).then((response) => {
|
||||
logger.default.info('Successfully removed track from favorites')
|
||||
}, (response) => {
|
||||
logger.default.info('Error while removing track from favorites')
|
||||
|
@ -57,9 +51,8 @@ export default {
|
|||
},
|
||||
fetch ({dispatch, state, commit}, url) {
|
||||
// will fetch favorites by batches from API to have them locally
|
||||
url = url || FAVORITES_URL
|
||||
let resource = Vue.resource(url)
|
||||
resource.get().then((response) => {
|
||||
url = url || 'favorites/tracks/'
|
||||
return axios.get(url).then((response) => {
|
||||
logger.default.info('Fetched a batch of ' + response.data.results.length + ' favorites')
|
||||
response.data.results.forEach(result => {
|
||||
commit('track', {id: result.track, value: true})
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Vue from 'vue'
|
||||
import config from '@/config'
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
import time from '@/utils/time'
|
||||
|
||||
|
@ -61,8 +60,8 @@ export default {
|
|||
}
|
||||
},
|
||||
actions: {
|
||||
incrementVolume (context, value) {
|
||||
context.commit('volume', context.state.volume + value)
|
||||
incrementVolume ({commit, state}, value) {
|
||||
commit('volume', state.volume + value)
|
||||
},
|
||||
stop (context) {
|
||||
},
|
||||
|
@ -70,9 +69,7 @@ export default {
|
|||
commit('playing', !state.playing)
|
||||
},
|
||||
trackListened ({commit}, track) {
|
||||
let url = config.API_URL + 'history/listenings/'
|
||||
let resource = Vue.resource(url)
|
||||
resource.save({}, {'track': track.id}).then((response) => {}, (response) => {
|
||||
return axios.post('history/listenings/', {'track': track.id}).then((response) => {}, (response) => {
|
||||
logger.default.error('Could not record track in history')
|
||||
})
|
||||
},
|
||||
|
|
|
@ -55,33 +55,32 @@ export default {
|
|||
}
|
||||
},
|
||||
actions: {
|
||||
append (context, {track, index, skipPlay}) {
|
||||
index = index || context.state.tracks.length
|
||||
if (index > context.state.tracks.length - 1) {
|
||||
append ({commit, state, dispatch}, {track, index, skipPlay}) {
|
||||
index = index || state.tracks.length
|
||||
if (index > state.tracks.length - 1) {
|
||||
// we simply push to the end
|
||||
context.commit('insert', {track, index: context.state.tracks.length})
|
||||
commit('insert', {track, index: state.tracks.length})
|
||||
} else {
|
||||
// we insert the track at given position
|
||||
context.commit('insert', {track, index})
|
||||
commit('insert', {track, index})
|
||||
}
|
||||
if (!skipPlay) {
|
||||
context.dispatch('resume')
|
||||
dispatch('resume')
|
||||
}
|
||||
// this.cache()
|
||||
},
|
||||
|
||||
appendMany (context, {tracks, index}) {
|
||||
appendMany ({state, dispatch}, {tracks, index}) {
|
||||
logger.default.info('Appending many tracks to the queue', tracks.map(e => { return e.title }))
|
||||
if (context.state.tracks.length === 0) {
|
||||
if (state.tracks.length === 0) {
|
||||
index = 0
|
||||
} else {
|
||||
index = index || context.state.tracks.length
|
||||
index = index || state.tracks.length
|
||||
}
|
||||
tracks.forEach((t) => {
|
||||
context.dispatch('append', {track: t, index: index, skipPlay: true})
|
||||
dispatch('append', {track: t, index: index, skipPlay: true})
|
||||
index += 1
|
||||
})
|
||||
context.dispatch('resume')
|
||||
dispatch('resume')
|
||||
},
|
||||
|
||||
cleanTrack ({state, dispatch, commit}, index) {
|
||||
|
@ -100,14 +99,14 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
resume (context) {
|
||||
if (context.state.ended | context.rootState.player.errored) {
|
||||
context.dispatch('next')
|
||||
resume ({state, dispatch, rootState}) {
|
||||
if (state.ended | rootState.player.errored) {
|
||||
dispatch('next')
|
||||
}
|
||||
},
|
||||
previous (context) {
|
||||
if (context.state.currentIndex > 0) {
|
||||
context.dispatch('currentIndex', context.state.currentIndex - 1)
|
||||
previous ({state, dispatch}) {
|
||||
if (state.currentIndex > 0) {
|
||||
dispatch('currentIndex', state.currentIndex - 1)
|
||||
}
|
||||
},
|
||||
next ({state, dispatch, commit, rootState}) {
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import Vue from 'vue'
|
||||
import config from '@/config'
|
||||
import axios from 'axios'
|
||||
import logger from '@/logging'
|
||||
|
||||
const CREATE_RADIO_URL = config.API_URL + 'radios/sessions/'
|
||||
const GET_TRACK_URL = config.API_URL + 'radios/tracks/'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
|
@ -39,13 +35,12 @@ export default {
|
|||
},
|
||||
actions: {
|
||||
start ({commit, dispatch}, {type, objectId, customRadioId}) {
|
||||
let resource = Vue.resource(CREATE_RADIO_URL)
|
||||
var params = {
|
||||
radio_type: type,
|
||||
related_object_id: objectId,
|
||||
custom_radio: customRadioId
|
||||
}
|
||||
resource.save({}, params).then((response) => {
|
||||
return axios.post('radios/sessions/', params).then((response) => {
|
||||
logger.default.info('Successfully started radio ', type)
|
||||
commit('current', {type, objectId, session: response.data.id, customRadioId})
|
||||
commit('running', true)
|
||||
|
@ -62,12 +57,10 @@ export default {
|
|||
if (!state.running) {
|
||||
return
|
||||
}
|
||||
let resource = Vue.resource(GET_TRACK_URL)
|
||||
var params = {
|
||||
session: state.current.session
|
||||
}
|
||||
let promise = resource.save({}, params)
|
||||
promise.then((response) => {
|
||||
return axios.post('radios/tracks/', params).then((response) => {
|
||||
logger.default.info('Adding track to queue from radio')
|
||||
dispatch('queue/append', {track: response.data.track}, {root: true})
|
||||
}, (response) => {
|
||||
|
|
|
@ -12,12 +12,17 @@ module.exports = function (config) {
|
|||
// http://karma-runner.github.io/0.13/config/browsers.html
|
||||
// 2. add it to the `browsers` array below.
|
||||
browsers: ['PhantomJS'],
|
||||
frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
|
||||
frameworks: ['mocha', 'sinon-stub-promise', 'sinon-chai', 'phantomjs-shim'],
|
||||
reporters: ['spec', 'coverage'],
|
||||
files: ['./index.js'],
|
||||
files: [
|
||||
'../../node_modules/es6-promise/dist/es6-promise.auto.js',
|
||||
'./index.js'
|
||||
],
|
||||
preprocessors: {
|
||||
'./index.js': ['webpack', 'sourcemap']
|
||||
},
|
||||
captureTimeout: 15000,
|
||||
retryLimit: 1,
|
||||
webpack: webpackConfig,
|
||||
webpackMiddleware: {
|
||||
noInfo: true
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import Vue from 'vue'
|
||||
import Hello from '@/components/Hello'
|
||||
|
||||
describe('Hello.vue', () => {
|
||||
it('should render correct contents', () => {
|
||||
const Constructor = Vue.extend(Hello)
|
||||
const vm = new Constructor().$mount()
|
||||
expect(vm.$el.querySelector('.hello h1').textContent)
|
||||
.to.equal('Welcome to Your Vue.js App')
|
||||
})
|
||||
})
|
|
@ -0,0 +1,200 @@
|
|||
var sinon = require('sinon')
|
||||
import moxios from 'moxios'
|
||||
import store from '@/store/auth'
|
||||
|
||||
import { testAction } from '../../utils'
|
||||
|
||||
describe('store/auth', () => {
|
||||
var sandbox
|
||||
|
||||
beforeEach(function () {
|
||||
sandbox = sinon.sandbox.create()
|
||||
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',
|
||||
tokenData: '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.tokenData).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)
|
||||
expect(state.tokenData).to.deep.equal({})
|
||||
})
|
||||
it('token real', () => {
|
||||
// generated on http://kjur.github.io/jsjws/tool_jwt.html
|
||||
const state = {}
|
||||
let token = 'eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2p3dC1pZHAuZXhhbXBsZS5jb20iLCJzdWIiOiJtYWlsdG86bWlrZUBleGFtcGxlLmNvbSIsIm5iZiI6MTUxNTUzMzQyOSwiZXhwIjoxNTE1NTM3MDI5LCJpYXQiOjE1MTU1MzM0MjksImp0aSI6ImlkMTIzNDU2IiwidHlwIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9yZWdpc3RlciJ9.'
|
||||
let tokenData = {
|
||||
iss: 'https://jwt-idp.example.com',
|
||||
sub: 'mailto:mike@example.com',
|
||||
nbf: 1515533429,
|
||||
exp: 1515537029,
|
||||
iat: 1515533429,
|
||||
jti: 'id123456',
|
||||
typ: 'https://example.com/register'
|
||||
}
|
||||
store.mutations.token(state, token)
|
||||
expect(state.token).to.equal(token)
|
||||
expect(state.tokenData).to.deep.equal(tokenData)
|
||||
})
|
||||
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 = { token: 'helloworld' }
|
||||
expect(store.getters['header'](state)).to.equal('JWT helloworld')
|
||||
})
|
||||
})
|
||||
describe('actions', () => {
|
||||
it('logout', (done) => {
|
||||
testAction({
|
||||
action: store.actions.logout,
|
||||
params: {state: {}},
|
||||
expectedMutations: [
|
||||
{ type: 'authenticated', payload: false }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('check jwt null', (done) => {
|
||||
testAction({
|
||||
action: store.actions.check,
|
||||
params: {state: {}},
|
||||
expectedMutations: [
|
||||
{ type: 'authenticated', payload: false }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('check jwt set', (done) => {
|
||||
testAction({
|
||||
action: store.actions.check,
|
||||
params: {state: {token: 'test', username: 'user'}},
|
||||
expectedMutations: [
|
||||
{ type: 'authenticated', payload: true },
|
||||
{ type: 'username', payload: 'user' },
|
||||
{ type: 'token', payload: 'test' }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'fetchProfile' },
|
||||
{ type: 'refreshToken' }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('login success', (done) => {
|
||||
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' },
|
||||
{ type: 'username', payload: 'bob' },
|
||||
{ type: 'authenticated', payload: true }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'fetchProfile' }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('login error', (done) => {
|
||||
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()
|
||||
})
|
||||
})
|
||||
it('fetchProfile', (done) => {
|
||||
const profile = {
|
||||
username: 'bob',
|
||||
permissions: {
|
||||
admin: {
|
||||
status: true
|
||||
}
|
||||
}
|
||||
}
|
||||
moxios.stubRequest('users/users/me/', {
|
||||
status: 200,
|
||||
response: profile
|
||||
})
|
||||
testAction({
|
||||
action: store.actions.fetchProfile,
|
||||
expectedMutations: [
|
||||
{ type: 'profile', payload: profile },
|
||||
{ type: 'permission', payload: {key: 'admin', status: true} }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'favorites/fetch', payload: null, options: {root: true} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('refreshToken', (done) => {
|
||||
moxios.stubRequest('token/refresh/', {
|
||||
status: 200,
|
||||
response: {token: 'newtoken'}
|
||||
})
|
||||
testAction({
|
||||
action: store.actions.refreshToken,
|
||||
params: {state: {token: 'oldtoken'}},
|
||||
expectedMutations: [
|
||||
{ type: 'token', payload: 'newtoken' }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,52 @@
|
|||
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', (done) => {
|
||||
testAction({
|
||||
action: store.actions.toggle,
|
||||
payload: 1,
|
||||
params: {getters: {isFavorite: () => false}},
|
||||
expectedActions: [
|
||||
{ type: 'set', payload: {id: 1, value: true} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('toggle true', (done) => {
|
||||
testAction({
|
||||
action: store.actions.toggle,
|
||||
payload: 1,
|
||||
params: {getters: {isFavorite: () => true}},
|
||||
expectedActions: [
|
||||
{ type: 'set', payload: {id: 1, value: false} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,153 @@
|
|||
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)
|
||||
})
|
||||
})
|
||||
describe('getters', () => {
|
||||
it('durationFormatted', () => {
|
||||
const state = { duration: 12.51 }
|
||||
expect(store.getters['durationFormatted'](state)).to.equal('00:13')
|
||||
})
|
||||
it('currentTimeFormatted', () => {
|
||||
const state = { currentTime: 12.51 }
|
||||
expect(store.getters['currentTimeFormatted'](state)).to.equal('00:13')
|
||||
})
|
||||
it('progress', () => {
|
||||
const state = { currentTime: 4, duration: 10 }
|
||||
expect(store.getters['progress'](state)).to.equal(40)
|
||||
})
|
||||
})
|
||||
describe('actions', () => {
|
||||
it('incrementVolume', (done) => {
|
||||
testAction({
|
||||
action: store.actions.incrementVolume,
|
||||
payload: 0.2,
|
||||
params: {state: {volume: 0.7}},
|
||||
expectedMutations: [
|
||||
{ type: 'volume', payload: 0.7 + 0.2 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('toggle play false', (done) => {
|
||||
testAction({
|
||||
action: store.actions.togglePlay,
|
||||
params: {state: {playing: false}},
|
||||
expectedMutations: [
|
||||
{ type: 'playing', payload: true }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('toggle play true', (done) => {
|
||||
testAction({
|
||||
action: store.actions.togglePlay,
|
||||
params: {state: {playing: true}},
|
||||
expectedMutations: [
|
||||
{ type: 'playing', payload: false }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('trackEnded', (done) => {
|
||||
testAction({
|
||||
action: store.actions.trackEnded,
|
||||
payload: {test: 'track'},
|
||||
expectedActions: [
|
||||
{ type: 'trackListened', payload: {test: 'track'} },
|
||||
{ type: 'queue/next', payload: null, options: {root: true} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('trackErrored', (done) => {
|
||||
testAction({
|
||||
action: store.actions.trackErrored,
|
||||
payload: {test: 'track'},
|
||||
expectedMutations: [
|
||||
{ type: 'errored', payload: true }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'queue/next', payload: null, options: {root: true} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('updateProgress', (done) => {
|
||||
testAction({
|
||||
action: store.actions.updateProgress,
|
||||
payload: 1,
|
||||
expectedMutations: [
|
||||
{ type: 'currentTime', payload: 1 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,333 @@
|
|||
var sinon = require('sinon')
|
||||
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.sandbox.create()
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
it('hasPrevious true', () => {
|
||||
const state = { currentIndex: 1 }
|
||||
expect(store.getters['hasPrevious'](state)).to.equal(true)
|
||||
})
|
||||
it('hasPrevious false', () => {
|
||||
const state = { currentIndex: 0 }
|
||||
expect(store.getters['hasPrevious'](state)).to.equal(false)
|
||||
})
|
||||
})
|
||||
describe('actions', () => {
|
||||
it('append at end', (done) => {
|
||||
testAction({
|
||||
action: store.actions.append,
|
||||
payload: {track: 4, skipPlay: true},
|
||||
params: {state: {tracks: [1, 2, 3]}},
|
||||
expectedMutations: [
|
||||
{ type: 'insert', payload: {track: 4, index: 3} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('append at index', (done) => {
|
||||
testAction({
|
||||
action: store.actions.append,
|
||||
payload: {track: 2, index: 1, skipPlay: true},
|
||||
params: {state: {tracks: [1, 3]}},
|
||||
expectedMutations: [
|
||||
{ type: 'insert', payload: {track: 2, index: 1} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('append and play', (done) => {
|
||||
testAction({
|
||||
action: store.actions.append,
|
||||
payload: {track: 3},
|
||||
params: {state: {tracks: [1, 2]}},
|
||||
expectedMutations: [
|
||||
{ type: 'insert', payload: {track: 3, index: 2} }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'resume' }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('appendMany', (done) => {
|
||||
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, skipPlay: true} },
|
||||
{ type: 'append', payload: {track: tracks[1], index: 1, skipPlay: true} },
|
||||
{ type: 'resume' }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('appendMany at index', (done) => {
|
||||
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, skipPlay: true} },
|
||||
{ type: 'append', payload: {track: tracks[1], index: 2, skipPlay: true} },
|
||||
{ type: 'resume' }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('cleanTrack after current', (done) => {
|
||||
testAction({
|
||||
action: store.actions.cleanTrack,
|
||||
payload: 3,
|
||||
params: {state: {currentIndex: 2}},
|
||||
expectedMutations: [
|
||||
{ type: 'splice', payload: {start: 3, size: 1} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('cleanTrack before current', (done) => {
|
||||
testAction({
|
||||
action: store.actions.cleanTrack,
|
||||
payload: 1,
|
||||
params: {state: {currentIndex: 2}},
|
||||
expectedMutations: [
|
||||
{ type: 'splice', payload: {start: 1, size: 1} }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'currentIndex', payload: 1 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('cleanTrack current', (done) => {
|
||||
testAction({
|
||||
action: store.actions.cleanTrack,
|
||||
payload: 2,
|
||||
params: {state: {currentIndex: 2}},
|
||||
expectedMutations: [
|
||||
{ type: 'splice', payload: {start: 2, size: 1} }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'player/stop', payload: null, options: {root: true} },
|
||||
{ type: 'currentIndex', payload: 2 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('resume when ended', (done) => {
|
||||
testAction({
|
||||
action: store.actions.resume,
|
||||
params: {state: {ended: true}, rootState: {player: {errored: false}}},
|
||||
expectedActions: [
|
||||
{ type: 'next' }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('resume when errored', (done) => {
|
||||
testAction({
|
||||
action: store.actions.resume,
|
||||
params: {state: {ended: false}, rootState: {player: {errored: true}}},
|
||||
expectedActions: [
|
||||
{ type: 'next' }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('skip resume when not ended or not error', (done) => {
|
||||
testAction({
|
||||
action: store.actions.resume,
|
||||
params: {state: {ended: false}, rootState: {player: {errored: false}}},
|
||||
expectedActions: []
|
||||
}, done)
|
||||
})
|
||||
it('previous when at beginning does nothing', (done) => {
|
||||
testAction({
|
||||
action: store.actions.previous,
|
||||
params: {state: {currentIndex: 0}},
|
||||
expectedActions: []
|
||||
}, done)
|
||||
})
|
||||
it('previous', (done) => {
|
||||
testAction({
|
||||
action: store.actions.previous,
|
||||
params: {state: {currentIndex: 1}},
|
||||
expectedActions: [
|
||||
{ type: 'currentIndex', payload: 0 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('next on last track when looping on queue', (done) => {
|
||||
testAction({
|
||||
action: store.actions.next,
|
||||
params: {state: {tracks: [1, 2], currentIndex: 1}, rootState: {player: {looping: 2}}},
|
||||
expectedActions: [
|
||||
{ type: 'currentIndex', payload: 0 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('next track when last track', (done) => {
|
||||
testAction({
|
||||
action: store.actions.next,
|
||||
params: {state: {tracks: [1, 2], currentIndex: 1}, rootState: {player: {looping: 0}}},
|
||||
expectedMutations: [
|
||||
{ type: 'ended', payload: true }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('next track when not last track', (done) => {
|
||||
testAction({
|
||||
action: store.actions.next,
|
||||
params: {state: {tracks: [1, 2], currentIndex: 0}, rootState: {player: {looping: 0}}},
|
||||
expectedActions: [
|
||||
{ type: 'currentIndex', payload: 1 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('currentIndex', (done) => {
|
||||
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: 'player/playing', payload: true, options: {root: true} },
|
||||
{ type: 'player/errored', payload: false, options: {root: true} },
|
||||
{ type: 'currentIndex', payload: 1 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('currentIndex with radio and many tracks remaining', (done) => {
|
||||
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: 'player/playing', payload: true, options: {root: true} },
|
||||
{ type: 'player/errored', payload: false, options: {root: true} },
|
||||
{ type: 'currentIndex', payload: 1 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('currentIndex with radio and less than two tracks remaining', (done) => {
|
||||
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: 'player/playing', payload: true, options: {root: true} },
|
||||
{ type: 'player/errored', payload: false, options: {root: true} },
|
||||
{ type: 'currentIndex', payload: 1 }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'radios/populateQueue', payload: null, options: {root: true} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('clean', (done) => {
|
||||
testAction({
|
||||
action: store.actions.clean,
|
||||
expectedMutations: [
|
||||
{ type: 'tracks', payload: [] },
|
||||
{ type: 'ended', payload: true }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'player/stop', payload: null, options: {root: true} },
|
||||
{ type: 'currentIndex', payload: -1 }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('shuffle', (done) => {
|
||||
let _shuffle = sandbox.stub(_, 'shuffle')
|
||||
let tracks = [1, 2, 3]
|
||||
let shuffledTracks = [2, 3, 1]
|
||||
_shuffle.returns(shuffledTracks)
|
||||
testAction({
|
||||
action: store.actions.shuffle,
|
||||
params: {state: {tracks: tracks}},
|
||||
expectedMutations: [
|
||||
{ type: 'tracks', payload: [] }
|
||||
],
|
||||
expectedActions: [
|
||||
{ type: 'appendMany', payload: {tracks: shuffledTracks} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,86 @@
|
|||
var sinon = require('sinon')
|
||||
import moxios from 'moxios'
|
||||
import store from '@/store/radios'
|
||||
import { testAction } from '../../utils'
|
||||
|
||||
describe('store/radios', () => {
|
||||
var sandbox
|
||||
|
||||
beforeEach(function () {
|
||||
sandbox = sinon.sandbox.create()
|
||||
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', (done) => {
|
||||
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' }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('stop', (done) => {
|
||||
testAction({
|
||||
action: store.actions.stop,
|
||||
expectedMutations: [
|
||||
{ type: 'current', payload: null },
|
||||
{ type: 'running', payload: false }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('populateQueue', (done) => {
|
||||
moxios.stubRequest('radios/tracks/', {
|
||||
status: 201,
|
||||
response: {track: {id: 1}}
|
||||
})
|
||||
testAction({
|
||||
action: store.actions.populateQueue,
|
||||
params: {state: {running: true, current: {session: 1}}},
|
||||
expectedActions: [
|
||||
{ type: 'queue/append', payload: {track: {id: 1}}, options: {root: true} }
|
||||
]
|
||||
}, done)
|
||||
})
|
||||
it('populateQueue does nothing when not running', (done) => {
|
||||
testAction({
|
||||
action: store.actions.populateQueue,
|
||||
params: {state: {running: false}},
|
||||
expectedActions: []
|
||||
}, done)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,73 @@
|
|||
// helper for testing action with expected mutations
|
||||
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]
|
||||
|
||||
try {
|
||||
expect(mutation.type).to.equal(type)
|
||||
if (payload) {
|
||||
expect(mutation.payload).to.deep.equal(payload)
|
||||
}
|
||||
} catch (error) {
|
||||
done(error)
|
||||
}
|
||||
|
||||
mutationsCount++
|
||||
if (isOver()) {
|
||||
done()
|
||||
}
|
||||
}
|
||||
// mock dispatch
|
||||
const dispatch = (type, payload, options) => {
|
||||
const a = expectedActions[actionsCount]
|
||||
try {
|
||||
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)
|
||||
}
|
||||
} catch (error) {
|
||||
done(error)
|
||||
}
|
||||
|
||||
actionsCount++
|
||||
if (isOver()) {
|
||||
done()
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
done()
|
||||
}
|
||||
}
|
||||
// call the action with mocked store and arguments
|
||||
let promise = action({ commit, dispatch, ...params }, payload)
|
||||
if (promise) {
|
||||
return promise.then(end)
|
||||
} else {
|
||||
return end()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue