Commit ba2de7c8 authored by Robert Knight's avatar Robert Knight

Convert "store" and "serviceUrl" services to use "apiRoutes"

Make these services use the "apiRoutes" service introduced in the
previous commit to fetch the API route directory and page links.
parent 5b214a6e
...@@ -33,9 +33,9 @@ var urlUtil = require('./util/url-util'); ...@@ -33,9 +33,9 @@ var urlUtil = require('./util/url-util');
* *
* @ngInject * @ngInject
*/ */
function serviceUrl(annotationUI, store) { function serviceUrl(annotationUI, apiRoutes) {
store.links() apiRoutes.links()
.then(annotationUI.updateLinks) .then(annotationUI.updateLinks)
.catch(function(error) { .catch(function(error) {
console.warn('The links API request was rejected: ' + error.message); console.warn('The links API request was rejected: ' + error.message);
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
var get = require('lodash.get'); var get = require('lodash.get');
var retryUtil = require('./retry-util');
var urlUtil = require('./util/url-util'); var urlUtil = require('./util/url-util');
/** /**
...@@ -150,15 +149,15 @@ function createAPICall($http, $q, links, route, tokenGetter) { ...@@ -150,15 +149,15 @@ function createAPICall($http, $q, links, route, tokenGetter) {
* *
* Returns an object that with keys that match the routes in * Returns an object that with keys that match the routes in
* the Hypothesis API (see http://h.readthedocs.io/en/latest/api/). * the Hypothesis API (see http://h.readthedocs.io/en/latest/api/).
*
* This service handles authenticated calls to the API, using the `auth` service
* to get auth tokens. The URLs for API endpoints are fetched from the `/api`
* endpoint, a responsibility delegated to the `apiRoutes` service which does
* not use authentication.
*/ */
// @ngInject // @ngInject
function store($http, $q, auth, settings) { function store($http, $q, apiRoutes, auth) {
var links = retryUtil.retryPromiseOperation(function () { var links = apiRoutes.routes();
return $http.get(settings.apiUrl);
}).then(function (response) {
return response.data.links;
});
function apiCall(route) { function apiCall(route) {
return createAPICall($http, $q, links, route, auth.tokenGetter); return createAPICall($http, $q, links, route, auth.tokenGetter);
} }
...@@ -178,7 +177,9 @@ function store($http, $q, auth, settings) { ...@@ -178,7 +177,9 @@ function store($http, $q, auth, settings) {
read: apiCall('profile.read'), read: apiCall('profile.read'),
update: apiCall('profile.update'), update: apiCall('profile.update'),
}, },
links: apiCall('links'),
// The `links` endpoint is not included here. Clients should fetch these
// from the `apiRoutes` service.
}; };
} }
......
...@@ -26,19 +26,19 @@ function createServiceUrl(linksPromise) { ...@@ -26,19 +26,19 @@ function createServiceUrl(linksPromise) {
var annotationUI = fakeAnnotationUI(); var annotationUI = fakeAnnotationUI();
var store = { var apiRoutes = {
links: sinon.stub().returns(linksPromise), links: sinon.stub().returns(linksPromise),
}; };
return { return {
annotationUI: annotationUI, annotationUI: annotationUI,
store: store, apiRoutes,
serviceUrl: serviceUrlFactory(annotationUI, store), serviceUrl: serviceUrlFactory(annotationUI, apiRoutes),
replaceURLParams: replaceURLParams, replaceURLParams: replaceURLParams,
}; };
} }
describe('links', function () { describe('sidebar.service-url', function () {
beforeEach(function() { beforeEach(function() {
sinon.stub(console, 'warn'); sinon.stub(console, 'warn');
...@@ -50,7 +50,7 @@ describe('links', function () { ...@@ -50,7 +50,7 @@ describe('links', function () {
context('before the API response has been received', function() { context('before the API response has been received', function() {
var serviceUrl; var serviceUrl;
var store; var apiRoutes;
beforeEach(function() { beforeEach(function() {
// Create a serviceUrl function with an unresolved Promise that will // Create a serviceUrl function with an unresolved Promise that will
...@@ -58,12 +58,12 @@ describe('links', function () { ...@@ -58,12 +58,12 @@ describe('links', function () {
var parts = createServiceUrl(new Promise(function() {})); var parts = createServiceUrl(new Promise(function() {}));
serviceUrl = parts.serviceUrl; serviceUrl = parts.serviceUrl;
store = parts.store; apiRoutes = parts.apiRoutes;
}); });
it('sends one API request for the links at boot time', function() { it('sends one API request for the links at boot time', function() {
assert.calledOnce(store.links); assert.calledOnce(apiRoutes.links);
assert.isTrue(store.links.calledWithExactly()); assert.isTrue(apiRoutes.links.calledWithExactly());
}); });
it('returns an empty string for any link', function() { it('returns an empty string for any link', function() {
......
...@@ -5,56 +5,10 @@ var proxyquire = require('proxyquire'); ...@@ -5,56 +5,10 @@ var proxyquire = require('proxyquire');
var util = require('../../shared/test/util'); var util = require('../../shared/test/util');
describe('store', function () { // API route directory.
var $httpBackend = null; // This should mirror the structure (but not the exact URLs) of
var sandbox = null; // https://hypothes.is/api/.
var store = null; var routes = {
before(function () {
angular.module('h')
.service('store', proxyquire('../store', util.noCallThru({
angular: angular,
'./retry-util': {
retryPromiseOperation: function (fn) {
return fn();
},
},
})));
});
beforeEach(function () {
sandbox = sinon.sandbox.create();
var fakeAuth = {};
angular.mock.module('h', {
auth: fakeAuth,
settings: {apiUrl: 'http://example.com/api/'},
});
angular.mock.inject(function (_$q_) {
var $q = _$q_;
fakeAuth.tokenGetter = function () {
return $q.resolve('faketoken');
};
});
});
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
sandbox.restore();
});
beforeEach(angular.mock.inject(function (_$httpBackend_, _store_) {
$httpBackend = _$httpBackend_;
store = _store_;
$httpBackend.expectGET('http://example.com/api/').respond({
// Return an API route directory.
// This should mirror the structure (but not the exact URLs) of
// https://hypothes.is/api/.
links: {
annotation: { annotation: {
create: { create: {
method: 'POST', method: 'POST',
...@@ -96,9 +50,59 @@ describe('store', function () { ...@@ -96,9 +50,59 @@ describe('store', function () {
url: 'http://example.com/api/profile', url: 'http://example.com/api/profile',
}, },
}, },
};
describe('sidebar.store', function () {
var $httpBackend = null;
var sandbox = null;
var store = null;
before(function () {
angular.module('h', [])
.service('store', proxyquire('../store', util.noCallThru({
angular: angular,
'./retry-util': {
retryPromiseOperation: function (fn) {
return fn();
},
}, },
})));
}); });
$httpBackend.flush();
beforeEach(function () {
sandbox = sinon.sandbox.create();
var fakeApiRoutes = {
links: sinon.stub(),
routes: sinon.stub(),
};
var fakeAuth = {};
angular.mock.module('h', {
apiRoutes: fakeApiRoutes,
auth: fakeAuth,
settings: {apiUrl: 'http://example.com/api/'},
});
angular.mock.inject(function (_$q_) {
var $q = _$q_;
fakeAuth.tokenGetter = function () {
return $q.resolve('faketoken');
};
fakeApiRoutes.routes.returns($q.resolve(routes));
});
});
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
sandbox.restore();
});
beforeEach(angular.mock.inject(function (_$httpBackend_, _store_) {
$httpBackend = _$httpBackend_;
store = _store_;
})); }));
it('saves a new annotation', function (done) { it('saves a new annotation', function (done) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment