Skip to content

Commit

Permalink
Big refactor to clean the code and improve the tests
Browse files Browse the repository at this point in the history
  • Loading branch information
davibusanello committed Oct 15, 2018
1 parent 21a921b commit e37eda4
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 198 deletions.
15 changes: 15 additions & 0 deletions examples/albums.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import SpotifyWrapper from '../src/index';

global.fetch = require('node-fetch');

const spotify = new SpotifyWrapper({
token: '',
});

const albums = spotify.search.albums('Incubus');
// console.log(albums);

albums.then((data) => {
data.albums.items.map(item => console.log(item.name));
})
.catch(error => console.log(error));
30 changes: 30 additions & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Spotify Wrapper Test</title>
</head>
<body>
<div id="albums"></div>

<script src="../dist/spotify-wrapper.umd.js"></script>
<script>
const spotify = new SpotifyWrapper({
token: '',
});
const albums = spotify.search.albums('Incubus');
const albumsEl = document.getElementById('albums');

albums
.then(data => {
markup = data.albums.items.map(item =>
`<img src='${item.images[0].url}' alt='${item.name}' />`
).join('');

albumsEl.innerHTML = markup;
});
</script>
</body>
</html>
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spotify-wrapper-js",
"version": "0.0.5",
"name": "davibusanello-spotify-wrapper",
"version": "0.0.8",
"description": "A wrapper to work with the Spotify Web API.",
"main": "lib/index.js",
"scripts": {
Expand Down
15 changes: 7 additions & 8 deletions src/album.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/* global fetch */

import API_URL from './config';
import toJSON from './utils';

export const getAlbum = id => fetch(`${API_URL}/albums/${id}`).then(toJSON);
export const getAlbums = id => fetch(`${API_URL}/albums/?ids=${id}`).then(toJSON);
export const getAlbumTracks = id => fetch(`${API_URL}/albums/${id}/tracks`).then(toJSON);
export default function album() {
return {
getAlbum: id => this.request(`${this.apiURL}/albums/${id}`),
getAlbums: id => this.request(`${this.apiURL}/albums/?ids=${id}`),
getTracks: id => this.request(`${this.apiURL}/albums/${id}/tracks`),
};
}
55 changes: 35 additions & 20 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
import {
search,
searchArtists,
searchAlbums,
searchPlaylists,
} from './search';
/* global fetch */
import search from './search';

import {
getAlbum,
getAlbums,
getAlbumTracks,
} from './album';
import album from './album';

module.exports = {
search,
searchArtists,
searchAlbums,
searchPlaylists,
getAlbum,
getAlbums,
getAlbumTracks,
};
import API_URL from './config';
import toJSON from './utils';

export default class SpotifyWrapper {
constructor(options) {
this.apiURL = options.apiURL || API_URL;
this.token = options.token;

this.album = album.bind(this)();
this.search = search.bind(this)();
}

/**
* Make the requests to the endpoints
* @param {String} url
*/
request(url) {
// Regex to verify the URL
const isValidUrl = new RegExp(/^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/);
if (!isValidUrl.test(url)) throw new TypeError('Invalid URL');

const headers = {
headers: {
Authorization: `Bearer ${this.token}`,
},
};

return fetch(url, headers)
.then(toJSON)
.catch(error => error);
}
}
31 changes: 11 additions & 20 deletions src/search.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
/* global fetch */
import API_URL from './config';
import toJSON from './utils';
function searcher(type, query) {
return this.request(`${this.apiURL}/search?q=${query}&type=${type}`);
}

export const search = (query, type) => {
fetch(`${API_URL}/search?q=${query}&type=${type}`)
.then(toJSON);
};

export const searchAlbums = (query) => {
search(query, 'album');
};
export const searchArtists = (query) => {
search(query, 'artist');
};
export const searchTracks = (query) => {
search(query, 'track');
};
export const searchPlaylists = (query) => {
search(query, 'playlist');
};
export default function search() {
return {
artists: searcher.bind(this, 'artist'),
albums: searcher.bind(this, 'album'),
tracks: searcher.bind(this, 'track'),
playlists: searcher.bind(this, 'playlist'),
};
}
5 changes: 4 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
const toJSON = data => data.json();
const toJSON = (data) => {
if (typeof data === 'undefined') throw new TypeError('data is undefined');
return data.json();
};
export default toJSON;
55 changes: 28 additions & 27 deletions tests/album.spec.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import chai, {
expect,
} from 'chai';
import chai, { expect } from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';

import { getAlbum, getAlbums, getAlbumTracks } from '../src/album';
import SpotifyWrapper from '../src/index';

chai.use(sinonChai);

global.fetch = require('node-fetch');


describe('Album', () => {
let spotify;
let stubedFetch;
let promise;

beforeEach(() => {
spotify = new SpotifyWrapper({
token: 'foo',
});

stubedFetch = sinon.stub(global, 'fetch');
promise = stubedFetch.resolves({
album: 'name',
json: () => ({
album: 'name',
}),
});
});

Expand All @@ -27,36 +32,36 @@ describe('Album', () => {

describe('smoke tests', () => {
it('should have getAlbum method', () => {
expect(getAlbum).to.exist;
expect(spotify.album.getAlbum).to.exist;
});

it('should have getAlbums method', () => {
expect(getAlbums).to.exist;
expect(spotify.album.getAlbums).to.exist;
});

it('should have getAlbumTracks method', () => {
expect(getAlbumTracks).to.exist;
it('should have getTracks method', () => {
expect(spotify.album.getTracks).to.exist;
});
});

describe('getAlbum', () => {
it('should call fetch method', () => {
const album = getAlbum();
const album = spotify.album.getAlbum();
expect(stubedFetch).to.have.been.calledOnce;
});

it('should call fetch with the correct URL', () => {
const album = getAlbum('4aawyAB9vmqN3uQ7FjRGTy');
const album = spotify.album.getAlbum('4aawyAB9vmqN3uQ7FjRGTy');
expect(stubedFetch).to.have.been
.calledWith('https://api.spotify.com/v1/albums/4aawyAB9vmqN3uQ7FjRGTy');

const album2 = getAlbum('4aawyAB9vmqN3uQ7FjRGTk');
const album2 = spotify.album.getAlbum('4aawyAB9vmqN3uQ7FjRGTk');
expect(stubedFetch).to.have.been
.calledWith('https://api.spotify.com/v1/albums/4aawyAB9vmqN3uQ7FjRGTk');
});

it('should return the correct data from Promise', () => {
const album = getAlbum('4aawyAB9vmqN3uQ7FjRGTy');
const album = spotify.album.getAlbum('4aawyAB9vmqN3uQ7FjRGTy');
album.then((data) => {
expect(data).to.be.eql({
album: 'name',
Expand All @@ -67,44 +72,40 @@ describe('Album', () => {

describe('getAlbums', () => {
it('should call fetch method', () => {
const albums = getAlbums();
const albums = spotify.album.getAlbums();
expect(stubedFetch).to.have.been.calledOnce;
});

it('should call fetch with the correct URL', () => {
const albums = getAlbums(['4aawyAB9vmqN3uQ7FjRGTy', '4aawyAB9vmqN3uQ7FjRGTk']);
const albums = spotify.album.getAlbums(['4aawyAB9vmqN3uQ7FjRGTy', '4aawyAB9vmqN3uQ7FjRGTk']);
expect(stubedFetch).to.have.been
.calledWith('https://api.spotify.com/v1/albums/?ids=4aawyAB9vmqN3uQ7FjRGTy,4aawyAB9vmqN3uQ7FjRGTk');
});

it('should return the correct data from Promise', () => {
const albums = getAlbums(['4aawyAB9vmqN3uQ7FjRGTy', '4aawyAB9vmqN3uQ7FjRGTk']);
const albums = spotify.album.getAlbums(['4aawyAB9vmqN3uQ7FjRGTy', '4aawyAB9vmqN3uQ7FjRGTk']);
albums.then((data) => {
expect(data).to.be.eql({
album: 'name',
});
expect(data).to.be.eql({ album: 'name' });
});
});
});

describe('getAlbumsTracks', () => {
describe('getTracks', () => {
it('should call fetch method', () => {
const tracks = getAlbumTracks();
const tracks = spotify.album.getTracks();
expect(stubedFetch).to.have.been.calledOnce;
});

it('should call fetch with the correct URL', () => {
const tracks = getAlbumTracks('4aawyAB9vmqN3uQ7FjRGTy');
const tracks = spotify.album.getTracks('4aawyAB9vmqN3uQ7FjRGTy');
expect(stubedFetch).to.have.been
.calledWith('https://api.spotify.com/v1/albums/4aawyAB9vmqN3uQ7FjRGTy/tracks');
});

it('should return the correct data from Promise', () => {
const tracks = getAlbumTracks('4aawyAB9vmqN3uQ7FjRGTy');
const tracks = spotify.album.getTracks('4aawyAB9vmqN3uQ7FjRGTy');
tracks.then((data) => {
expect(data).to.be.eql({
album: 'name',
});
expect(data).to.be.eql({ album: 'name' });
});
});
});
Expand Down
90 changes: 90 additions & 0 deletions tests/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import chai, { expect } from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';

import SpotifyWrapper from '../src/index';

chai.use(sinonChai);

global.fetch = require('node-fetch');

describe('SpotifyWrapper Library', () => {
it('should create an instance of SpotifyWrapper', () => {
const spotify = new SpotifyWrapper({});
expect(spotify).to.be.an.instanceof(SpotifyWrapper);
});

it('should receive apiURL as an option', () => {
const spotify = new SpotifyWrapper({
apiURL: 'bablabla',
});
expect(spotify.apiURL).to.be.equal('bablabla');
});

it('should use the default apiURL if not provided', () => {
const spotify = new SpotifyWrapper({});
expect(spotify.apiURL).to.be.equal('https://api.spotify.com/v1');
});

it('should receive token as an option', () => {
const spotify = new SpotifyWrapper({
token: 'foo',
});
expect(spotify.token).to.be.equal('foo');
});

describe('request method', () => {
let stubedFetch;
let promise;

beforeEach(() => {
stubedFetch = sinon.stub(global, 'fetch');
promise = stubedFetch.returns(Promise.resolve());
});

afterEach(() => {
stubedFetch.restore();
});

it('should have request method', () => {
const spotify = new SpotifyWrapper({});
expect(spotify.request).to.exist;
});

it('should throw TypeError when passed an invalid URL', () => {
const spotify = new SpotifyWrapper({
token: 'food',
});
expect(spotify.request.bind(spotify, 'url')).to.throw('Invalid URL');
});

it('should call fetch when request', () => {
const spotify = new SpotifyWrapper({
token: 'food',
});
spotify.request('https://api.spotify.com/v1');
expect(stubedFetch).to.have.been.calledOnce;
});

it('should call fetch with the right url passed', () => {
const spotify = new SpotifyWrapper({
token: 'food',
});
spotify.request('https://api.spotify.com/v1');
expect(stubedFetch).to.have.been.calledWith('https://api.spotify.com/v1');
});

it('should call fetch with the right headers passed', () => {
const spotify = new SpotifyWrapper({
token: 'food',
});
const headers = {
headers: {
Authorization: 'Bearer food',
},
};
spotify.request('https://api.spotify.com/v1');
expect(stubedFetch).to.have.been.calledWith('https://api.spotify.com/v1', headers);
});
});
});
Loading

0 comments on commit e37eda4

Please sign in to comment.