Skip to content
Snippets Groups Projects
Commit e0820dfa authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch 'feature/frontend-unittests' into 'develop'

Feature/frontend unittests

See merge request funkwhale/funkwhale!40
parents 2ec36d75 90611ffa
Branches
Tags 0.5
No related merge requests found
Showing
with 86 additions and 90 deletions
...@@ -2,7 +2,7 @@ variables: ...@@ -2,7 +2,7 @@ variables:
IMAGE_NAME: funkwhale/funkwhale IMAGE_NAME: funkwhale/funkwhale
IMAGE: $IMAGE_NAME:$CI_COMMIT_REF_NAME IMAGE: $IMAGE_NAME:$CI_COMMIT_REF_NAME
IMAGE_LATEST: $IMAGE_NAME:latest IMAGE_LATEST: $IMAGE_NAME:latest
PIP_CACHE_DIR: "$CI_PROJECT_DIR/pip-cache"
stages: stages:
...@@ -14,40 +14,61 @@ test_api: ...@@ -14,40 +14,61 @@ test_api:
services: services:
- postgres:9.4 - postgres:9.4
stage: test stage: test
image: funkwhale/funkwhale:base image: funkwhale/funkwhale:latest
cache:
key: "$CI_PROJECT_ID/pip_cache"
paths:
- "$PIP_CACHE_DIR"
variables: variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/pip-cache"
DATABASE_URL: "postgresql://postgres@postgres/postgres" DATABASE_URL: "postgresql://postgres@postgres/postgres"
before_script: before_script:
- python3 -m venv --copies virtualenv
- source virtualenv/bin/activate
- cd api - cd api
- pip install -r requirements/base.txt - pip install -r requirements/base.txt
- pip install -r requirements/local.txt - pip install -r requirements/local.txt
- pip install -r requirements/test.txt - pip install -r requirements/test.txt
script: script:
- pytest - pytest
tags:
- docker
test_front:
stage: test
image: node:9
before_script:
- cd front
script:
- yarn install
- yarn run unit
cache: cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME" key: "$CI_PROJECT_ID/front_dependencies"
paths: paths:
- "$CI_PROJECT_DIR/pip-cache" - front/node_modules
- front/yarn.lock
artifacts:
name: "front_${CI_COMMIT_REF_NAME}"
paths:
- front/dist/
tags: tags:
- docker - docker
build_front: build_front:
stage: build stage: build
image: node:6-alpine image: node:9
before_script: before_script:
- cd front - cd front
script: script:
- npm install - yarn install
- npm run build - yarn run build
cache: cache:
key: "$CI_COMMIT_REF_NAME" key: "$CI_PROJECT_ID/front_dependencies"
paths: paths:
- front/node_modules - front/node_modules
- front/yarn.lock
artifacts: artifacts:
name: "front_${CI_COMMIT_REF_NAME}" name: "front_${CI_COMMIT_REF_NAME}"
paths: paths:
......
...@@ -43,7 +43,7 @@ class TrackFavoriteViewSet(mixins.CreateModelMixin, ...@@ -43,7 +43,7 @@ class TrackFavoriteViewSet(mixins.CreateModelMixin,
favorite = models.TrackFavorite.add(track=track, user=self.request.user) favorite = models.TrackFavorite.add(track=track, user=self.request.user)
return favorite return favorite
@list_route(methods=['delete']) @list_route(methods=['delete', 'post'])
def remove(self, request, *args, **kwargs): def remove(self, request, *args, **kwargs):
try: try:
pk = int(request.data['track']) pk = int(request.data['track'])
......
...@@ -4,7 +4,7 @@ Populates the database with fake data ...@@ -4,7 +4,7 @@ Populates the database with fake data
import random import random
from funkwhale_api.music import models from funkwhale_api.music import models
from funkwhale_api.music.tests import factories from funkwhale_api.music import factories
def create_data(count=25): def create_data(count=25):
...@@ -19,4 +19,4 @@ def create_data(count=25): ...@@ -19,4 +19,4 @@ def create_data(count=25):
if __name__ == '__main__': if __name__ == '__main__':
main() create_data()
...@@ -47,8 +47,7 @@ mutagen>=1.39,<1.40 ...@@ -47,8 +47,7 @@ mutagen>=1.39,<1.40
# Until this is merged # Until this is merged
#django-taggit>=0.22,<0.23 django-taggit>=0.22,<0.23
git+https://github.com/alex/django-taggit.git@95776ac66948ed7ba7c12e35c1170551e3be66a5
# Until this is merged # Until this is merged
git+https://github.com/EliotBerriot/PyMemoize.git@django git+https://github.com/EliotBerriot/PyMemoize.git@django
# Until this is merged # Until this is merged
......
...@@ -58,11 +58,14 @@ def test_user_can_remove_favorite_via_api(logged_in_client, factories, client): ...@@ -58,11 +58,14 @@ def test_user_can_remove_favorite_via_api(logged_in_client, factories, client):
assert response.status_code == 204 assert response.status_code == 204
assert TrackFavorite.objects.count() == 0 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) favorite = factories['favorites.TrackFavorite'](user=logged_in_client.user)
url = reverse('api:v1:favorites:tracks-remove') 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}), url, json.dumps({'track': favorite.track.pk}),
content_type='application/json' content_type='application/json'
) )
......
...@@ -3,9 +3,7 @@ version: '2' ...@@ -3,9 +3,7 @@ version: '2'
services: services:
front: front:
build: build: front
dockerfile: docker/Dockerfile.dev
context: ./front
env_file: .env.dev env_file: .env.dev
environment: environment:
- "HOST=0.0.0.0" - "HOST=0.0.0.0"
......
FROM node:6-alpine FROM node:9
EXPOSE 8080 EXPOSE 8080
WORKDIR /app/
RUN mkdir /app
WORKDIR /app
ADD package.json . ADD package.json .
RUN yarn install --only=production
RUN yarn install --only=dev
VOLUME ["/app/node_modules"]
COPY . .
RUN npm install CMD ["npm", "run", "dev"]
ADD . .
RUN npm run build
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 @@ ...@@ -9,19 +9,21 @@
"start": "node build/dev-server.js", "start": "node build/dev-server.js",
"build": "node build/build.js", "build": "node build/build.js",
"unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run", "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", "e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e", "test": "npm run unit && npm run e2e",
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs" "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
}, },
"dependencies": { "dependencies": {
"axios": "^0.17.1",
"dateformat": "^2.0.0", "dateformat": "^2.0.0",
"js-logger": "^1.3.0", "js-logger": "^1.3.0",
"jwt-decode": "^2.2.0", "jwt-decode": "^2.2.0",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"moxios": "^0.4.0",
"semantic-ui-css": "^2.2.10", "semantic-ui-css": "^2.2.10",
"vue": "^2.3.3", "vue": "^2.3.3",
"vue-lazyload": "^1.1.4", "vue-lazyload": "^1.1.4",
"vue-resource": "^1.3.4",
"vue-router": "^2.3.1", "vue-router": "^2.3.1",
"vue-upload-component": "^2.7.4", "vue-upload-component": "^2.7.4",
"vuedraggable": "^2.14.1", "vuedraggable": "^2.14.1",
...@@ -46,6 +48,7 @@ ...@@ -46,6 +48,7 @@
"cross-env": "^4.0.0", "cross-env": "^4.0.0",
"cross-spawn": "^5.0.1", "cross-spawn": "^5.0.1",
"css-loader": "^0.28.0", "css-loader": "^0.28.0",
"es6-promise": "^4.2.2",
"eslint": "^3.19.0", "eslint": "^3.19.0",
"eslint-config-standard": "^6.2.1", "eslint-config-standard": "^6.2.1",
"eslint-friendly-formatter": "^2.0.7", "eslint-friendly-formatter": "^2.0.7",
...@@ -67,6 +70,7 @@ ...@@ -67,6 +70,7 @@
"karma-phantomjs-launcher": "^1.0.2", "karma-phantomjs-launcher": "^1.0.2",
"karma-phantomjs-shim": "^1.4.0", "karma-phantomjs-shim": "^1.4.0",
"karma-sinon-chai": "^1.3.1", "karma-sinon-chai": "^1.3.1",
"karma-sinon-stub-promise": "^1.0.0",
"karma-sourcemap-loader": "^0.3.7", "karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "0.0.30", "karma-spec-reporter": "0.0.30",
"karma-webpack": "^2.0.2", "karma-webpack": "^2.0.2",
...@@ -85,6 +89,7 @@ ...@@ -85,6 +89,7 @@
"shelljs": "^0.7.6", "shelljs": "^0.7.6",
"sinon": "^2.1.0", "sinon": "^2.1.0",
"sinon-chai": "^2.8.0", "sinon-chai": "^2.8.0",
"sinon-stub-promise": "^4.0.0",
"url-loader": "^0.5.8", "url-loader": "^0.5.8",
"vue-loader": "^12.1.0", "vue-loader": "^12.1.0",
"vue-style-loader": "^3.0.1", "vue-style-loader": "^3.0.1",
......
File moved
...@@ -29,13 +29,11 @@ ...@@ -29,13 +29,11 @@
</template> </template>
<script> <script>
import axios from 'axios'
import logger from '@/logging' import logger from '@/logging'
import backend from '@/audio/backend' import backend from '@/audio/backend'
import AlbumCard from '@/components/audio/album/Card' import AlbumCard from '@/components/audio/album/Card'
import ArtistCard from '@/components/audio/artist/Card' import ArtistCard from '@/components/audio/artist/Card'
import config from '@/config'
const SEARCH_URL = config.API_URL + 'search'
export default { export default {
components: { components: {
...@@ -73,17 +71,8 @@ export default { ...@@ -73,17 +71,8 @@ export default {
let params = { let params = {
query: this.query query: this.query
} }
this.$http.get(SEARCH_URL, { axios.get('search', {
params: params, params: params
before (request) {
// abort previous request, if exists
if (this.previousRequest) {
this.previousRequest.abort()
}
// set previous request on Vue instance
this.previousRequest = request
}
}).then((response) => { }).then((response) => {
self.results = self.castResults(response.data) self.results = self.castResults(response.data)
self.isLoading = false self.isLoading = false
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
</template> </template>
<script> <script>
import Vue from 'vue' import axios from 'axios'
import config from '@/config' import config from '@/config'
import logger from '@/logging' import logger from '@/logging'
...@@ -61,8 +61,8 @@ export default { ...@@ -61,8 +61,8 @@ export default {
new_password1: this.new_password, new_password1: this.new_password,
new_password2: this.new_password new_password2: this.new_password
} }
let resource = Vue.resource(config.BACKEND_URL + 'api/auth/registration/change-password/') let url = config.BACKEND_URL + 'api/auth/registration/change-password/'
return resource.save({}, credentials).then(response => { return axios.post(url, credentials).then(response => {
logger.default.info('Password successfully changed') logger.default.info('Password successfully changed')
self.$router.push('/profile/me') self.$router.push('/profile/me')
}, response => { }, response => {
......
...@@ -54,15 +54,15 @@ ...@@ -54,15 +54,15 @@
</template> </template>
<script> <script>
import axios from 'axios'
import $ from 'jquery' import $ from 'jquery'
import logger from '@/logging' import logger from '@/logging'
import config from '@/config'
import TrackTable from '@/components/audio/track/Table' import TrackTable from '@/components/audio/track/Table'
import RadioButton from '@/components/radios/Button' import RadioButton from '@/components/radios/Button'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import OrderingMixin from '@/components/mixins/Ordering' import OrderingMixin from '@/components/mixins/Ordering'
import PaginationMixin from '@/components/mixins/Pagination' import PaginationMixin from '@/components/mixins/Pagination'
const FAVORITES_URL = config.API_URL + 'tracks/' const FAVORITES_URL = 'tracks/'
export default { export default {
mixins: [OrderingMixin, PaginationMixin], mixins: [OrderingMixin, PaginationMixin],
...@@ -115,7 +115,7 @@ export default { ...@@ -115,7 +115,7 @@ export default {
ordering: this.getOrderingAsString() ordering: this.getOrderingAsString()
} }
logger.default.time('Loading user favorites') 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.results = response.data
self.nextLink = response.data.next self.nextLink = response.data.next
self.previousLink = response.data.previous self.previousLink = response.data.previous
......
...@@ -41,14 +41,13 @@ ...@@ -41,14 +41,13 @@
</template> </template>
<script> <script>
import axios from 'axios'
import logger from '@/logging' import logger from '@/logging'
import backend from '@/audio/backend' import backend from '@/audio/backend'
import PlayButton from '@/components/audio/PlayButton' import PlayButton from '@/components/audio/PlayButton'
import TrackTable from '@/components/audio/track/Table' import TrackTable from '@/components/audio/track/Table'
import config from '@/config'
const FETCH_URL = config.API_URL + 'albums/' const FETCH_URL = 'albums/'
export default { export default {
props: ['id'], props: ['id'],
...@@ -71,7 +70,7 @@ export default { ...@@ -71,7 +70,7 @@ export default {
this.isLoading = true this.isLoading = true
let url = FETCH_URL + this.id + '/' let url = FETCH_URL + this.id + '/'
logger.default.debug('Fetching album "' + 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.album = backend.Album.clean(response.data)
self.isLoading = false self.isLoading = false
}) })
......
...@@ -41,15 +41,14 @@ ...@@ -41,15 +41,14 @@
</template> </template>
<script> <script>
import axios from 'axios'
import logger from '@/logging' import logger from '@/logging'
import backend from '@/audio/backend' import backend from '@/audio/backend'
import AlbumCard from '@/components/audio/album/Card' import AlbumCard from '@/components/audio/album/Card'
import RadioButton from '@/components/radios/Button' import RadioButton from '@/components/radios/Button'
import PlayButton from '@/components/audio/PlayButton' import PlayButton from '@/components/audio/PlayButton'
import config from '@/config'
const FETCH_URL = config.API_URL + 'artists/' const FETCH_URL = 'artists/'
export default { export default {
props: ['id'], props: ['id'],
...@@ -74,7 +73,7 @@ export default { ...@@ -74,7 +73,7 @@ export default {
this.isLoading = true this.isLoading = true
let url = FETCH_URL + this.id + '/' let url = FETCH_URL + this.id + '/'
logger.default.debug('Fetching artist "' + 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.artist = response.data
self.albums = JSON.parse(JSON.stringify(self.artist.albums)).map((album) => { self.albums = JSON.parse(JSON.stringify(self.artist.albums)).map((album) => {
return backend.Album.clean(album) return backend.Album.clean(album)
......
...@@ -57,10 +57,10 @@ ...@@ -57,10 +57,10 @@
</template> </template>
<script> <script>
import axios from 'axios'
import _ from 'lodash' import _ from 'lodash'
import $ from 'jquery' import $ from 'jquery'
import config from '@/config'
import backend from '@/audio/backend' import backend from '@/audio/backend'
import logger from '@/logging' import logger from '@/logging'
...@@ -69,7 +69,7 @@ import PaginationMixin from '@/components/mixins/Pagination' ...@@ -69,7 +69,7 @@ import PaginationMixin from '@/components/mixins/Pagination'
import ArtistCard from '@/components/audio/artist/Card' import ArtistCard from '@/components/audio/artist/Card'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
const FETCH_URL = config.API_URL + 'artists/' const FETCH_URL = 'artists/'
export default { export default {
mixins: [OrderingMixin, PaginationMixin], mixins: [OrderingMixin, PaginationMixin],
...@@ -124,7 +124,7 @@ export default { ...@@ -124,7 +124,7 @@ export default {
ordering: this.getOrderingAsString() ordering: this.getOrderingAsString()
} }
logger.default.debug('Fetching artists') 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 = response.data
self.result.results.map((artist) => { self.result.results.map((artist) => {
var albums = JSON.parse(JSON.stringify(artist.albums)).map((album) => { var albums = JSON.parse(JSON.stringify(artist.albums)).map((album) => {
......
...@@ -24,14 +24,14 @@ ...@@ -24,14 +24,14 @@
</template> </template>
<script> <script>
import axios from 'axios'
import Search from '@/components/audio/Search' import Search from '@/components/audio/Search'
import backend from '@/audio/backend' import backend from '@/audio/backend'
import logger from '@/logging' import logger from '@/logging'
import ArtistCard from '@/components/audio/artist/Card' import ArtistCard from '@/components/audio/artist/Card'
import config from '@/config'
import RadioCard from '@/components/radios/Card' import RadioCard from '@/components/radios/Card'
const ARTISTS_URL = config.API_URL + 'artists/' const ARTISTS_URL = 'artists/'
export default { export default {
name: 'library', name: 'library',
...@@ -58,7 +58,7 @@ export default { ...@@ -58,7 +58,7 @@ export default {
} }
let url = ARTISTS_URL let url = ARTISTS_URL
logger.default.time('Loading latest artists') 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 = response.data.results
self.artists.map((artist) => { self.artists.map((artist) => {
var albums = JSON.parse(JSON.stringify(artist.albums)).map((album) => { var albums = JSON.parse(JSON.stringify(artist.albums)).map((album) => {
......
...@@ -59,10 +59,10 @@ ...@@ -59,10 +59,10 @@
</template> </template>
<script> <script>
import axios from 'axios'
import _ from 'lodash' import _ from 'lodash'
import $ from 'jquery' import $ from 'jquery'
import config from '@/config'
import logger from '@/logging' import logger from '@/logging'
import OrderingMixin from '@/components/mixins/Ordering' import OrderingMixin from '@/components/mixins/Ordering'
...@@ -70,7 +70,7 @@ import PaginationMixin from '@/components/mixins/Pagination' ...@@ -70,7 +70,7 @@ import PaginationMixin from '@/components/mixins/Pagination'
import RadioCard from '@/components/radios/Card' import RadioCard from '@/components/radios/Card'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
const FETCH_URL = config.API_URL + 'radios/radios/' const FETCH_URL = 'radios/radios/'
export default { export default {
mixins: [OrderingMixin, PaginationMixin], mixins: [OrderingMixin, PaginationMixin],
...@@ -125,7 +125,7 @@ export default { ...@@ -125,7 +125,7 @@ export default {
ordering: this.getOrderingAsString() ordering: this.getOrderingAsString()
} }
logger.default.debug('Fetching radios') 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.result = response.data
self.isLoading = false self.isLoading = false
}) })
......
...@@ -60,15 +60,14 @@ ...@@ -60,15 +60,14 @@
</template> </template>
<script> <script>
import axios from 'axios'
import url from '@/utils/url' import url from '@/utils/url'
import logger from '@/logging' import logger from '@/logging'
import backend from '@/audio/backend' import backend from '@/audio/backend'
import PlayButton from '@/components/audio/PlayButton' import PlayButton from '@/components/audio/PlayButton'
import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon' import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
import config from '@/config'
const FETCH_URL = config.API_URL + 'tracks/' const FETCH_URL = 'tracks/'
export default { export default {
props: ['id'], props: ['id'],
...@@ -94,7 +93,7 @@ export default { ...@@ -94,7 +93,7 @@ export default {
this.isLoadingTrack = true this.isLoadingTrack = true
let url = FETCH_URL + this.id + '/' let url = FETCH_URL + this.id + '/'
logger.default.debug('Fetching track "' + 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.track = response.data
self.isLoadingTrack = false self.isLoadingTrack = false
}) })
...@@ -104,7 +103,7 @@ export default { ...@@ -104,7 +103,7 @@ export default {
this.isLoadingLyrics = true this.isLoadingLyrics = true
let url = FETCH_URL + this.id + '/lyrics/' let url = FETCH_URL + this.id + '/lyrics/'
logger.default.debug('Fetching lyrics for track "' + this.id + '"') 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.lyrics = response.data
self.isLoadingLyrics = false self.isLoadingLyrics = false
}, (response) => { }, (response) => {
......
...@@ -37,8 +37,8 @@ ...@@ -37,8 +37,8 @@
<script> <script>
import Vue from 'vue' import Vue from 'vue'
import axios from 'axios'
import logger from '@/logging' import logger from '@/logging'
import config from '@/config'
import ImportMixin from './ImportMixin' import ImportMixin from './ImportMixin'
import ReleaseImport from './ReleaseImport' import ReleaseImport from './ReleaseImport'
...@@ -92,9 +92,8 @@ export default Vue.extend({ ...@@ -92,9 +92,8 @@ export default Vue.extend({
fetchReleaseGroupsData () { fetchReleaseGroupsData () {
let self = this let self = this
this.releaseGroups.forEach(group => { this.releaseGroups.forEach(group => {
let url = config.API_URL + 'providers/musicbrainz/releases/browse/' + group.id + '/' let url = 'providers/musicbrainz/releases/browse/' + group.id + '/'
let resource = Vue.resource(url) return axios.get(url).then((response) => {
resource.get({}).then((response) => {
logger.default.info('successfully fetched release group', group.id) logger.default.info('successfully fetched release group', group.id)
let release = response.data['release-list'].filter(r => { let release = response.data['release-list'].filter(r => {
return r.status === 'Official' return r.status === 'Official'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment