Commit 0204f7a8 authored by Nick Stenning's avatar Nick Stenning

Merge pull request #2962 from hypothesis/annotation-test-cleanup

Annotation test cleanup
parents 8c2d1df6 aab5355a
/**
* Utility functions for querying annotation metadata.
*/
/** Extract a URI, domain and title from the given domain model object.
*
* @param {object} annotation An annotation domain model object as received
* from the server-side API.
* @returns {object} An object with three properties extracted from the model:
* uri, domain and title.
*
*/
function extractDocumentMetadata(annotation) {
var document_;
var uri = annotation.uri;
var domain = new URL(uri).hostname;
if (annotation.document) {
if (uri.indexOf('urn') === 0) {
var i;
for (i = 0; i < annotation.document.link.length; i++) {
var link = annotation.document.link[i];
if (link.href.indexOf('urn:') === 0) {
continue;
}
uri = link.href;
break;
}
}
var documentTitle;
if (Array.isArray(annotation.document.title)) {
documentTitle = annotation.document.title[0];
} else {
documentTitle = annotation.document.title;
}
document_ = {
uri: uri,
domain: domain,
title: documentTitle || domain
};
} else {
document_ = {
uri: uri,
domain: domain,
title: domain
};
}
if (document_.title.length > 30) {
document_.title = document_.title.slice(0, 30) + '…';
}
return document_;
}
/** Return `true` if the given annotation is a reply, `false` otherwise. */
function isReply(annotation) {
return (annotation.references || []).length > 0;
}
/** Return `true` if the given annotation is new, `false` otherwise.
*
* "New" means this annotation has been newly created client-side and not
* saved to the server yet.
*/
function isNew(annotation) {
return !annotation.id;
}
module.exports = {
extractDocumentMetadata: extractDocumentMetadata,
isReply: isReply,
isNew: isNew,
};
...@@ -3,12 +3,17 @@ ...@@ -3,12 +3,17 @@
var Promise = require('core-js/library/es6/promise'); var Promise = require('core-js/library/es6/promise');
var annotationMetadata = require('../annotation-metadata');
var dateUtil = require('../date-util'); var dateUtil = require('../date-util');
var documentDomain = require('../filter/document-domain'); var documentDomain = require('../filter/document-domain');
var documentTitle = require('../filter/document-title'); var documentTitle = require('../filter/document-title');
var events = require('../events'); var events = require('../events');
var persona = require('../filter/persona'); var persona = require('../filter/persona');
var isNew = annotationMetadata.isNew;
var isReply = annotationMetadata.isReply;
var extractDocumentMetadata = annotationMetadata.extractDocumentMetadata;
/** Return a domainModel tags array from the given vm tags array. /** Return a domainModel tags array from the given vm tags array.
* *
* domainModel.tags and vm.form.tags use different formats. This * domainModel.tags and vm.form.tags use different formats. This
...@@ -43,71 +48,7 @@ function errorMessage(reason) { ...@@ -43,71 +48,7 @@ function errorMessage(reason) {
return message; return message;
} }
/** Extract a URI, domain and title from the given domain model object.
*
* @param {object} domainModel An annotation domain model object as received
* from the server-side API.
* @returns {object} An object with three properties extracted from the model:
* uri, domain and title.
*
*/
function extractDocumentMetadata(domainModel) {
var document_;
var uri = domainModel.uri;
var domain = new URL(uri).hostname;
if (domainModel.document) {
if (uri.indexOf('urn') === 0) {
var i;
for (i = 0; i < domainModel.document.link.length; i++) {
var link = domainModel.document.link[i];
if (link.href.indexOf('urn:') === 0) {
continue;
}
uri = link.href;
break;
}
}
var documentTitle;
if (Array.isArray(domainModel.document.title)) {
documentTitle = domainModel.document.title[0];
} else {
documentTitle = domainModel.document.title;
}
document_ = {
uri: uri,
domain: domain,
title: documentTitle || domain
};
} else {
document_ = {
uri: uri,
domain: domain,
title: domain
};
}
if (document_.title.length > 30) {
document_.title = document_.title.slice(0, 30) + '…';
}
return document_;
}
/** Return `true` if the given annotation is a reply, `false` otherwise. */
function isReply(domainModel) {
return (domainModel.references || []).length > 0;
}
/** Return `true` if the given annotation is new, `false` otherwise.
*
* "New" means this annotation has been newly created client-side and not
* saved to the server yet.
*/
function isNew(domainModel) {
return !domainModel.id;
}
/** Restore unsaved changes to this annotation from the drafts service. /** Restore unsaved changes to this annotation from the drafts service.
* *
...@@ -840,7 +781,6 @@ module.exports = { ...@@ -840,7 +781,6 @@ module.exports = {
// to be unit tested. // to be unit tested.
// FIXME: The code should be refactored to enable unit testing without having // FIXME: The code should be refactored to enable unit testing without having
// to do this. // to do this.
extractDocumentMetadata: extractDocumentMetadata,
link: link, link: link,
updateDomainModel: updateDomainModel, updateDomainModel: updateDomainModel,
......
'use strict'; 'use strict';
// converts a camelCase name into hyphenated ('camel-case') form, /**
// as Angular does when mapping directive names to tag names in HTML * Converts a camelCase name into hyphenated ('camel-case') form.
*
* This matches how Angular maps directive names to HTML tag names.
*/
function hyphenate(name) { function hyphenate(name) {
var uppercasePattern = /([A-Z])/g; var uppercasePattern = /([A-Z])/g;
return name.replace(uppercasePattern, '-$1').toLowerCase(); return name.replace(uppercasePattern, '-$1').toLowerCase();
} }
/**
* Helper for retrieving an Angular module in a test.
*
* Given the 'inject' function from the 'angular-mocks' module,
* retrieves an instance of the specified Angular module.
*/
function ngModule(inject, name) {
var module;
var helper = function (_module) {
module = _module;
};
// Tell Angular which module we want using $inject
// annotations. These take priority over function argument names.
helper.$inject = [name];
// inject() creates a new 'angular.$injector' service instance
// for the current test, if one has not already been created and then
// calls the passed function, injecting the modules it depends upon.
inject(helper);
return module;
}
/** /**
* A helper for instantiating an AngularJS directive in a unit test. * A helper for instantiating an AngularJS directive in a unit test.
* *
...@@ -124,5 +151,6 @@ function createDirective(document, name, attrs, initialScope, initialHtml, opts) ...@@ -124,5 +151,6 @@ function createDirective(document, name, attrs, initialScope, initialHtml, opts)
} }
module.exports = { module.exports = {
createDirective: createDirective createDirective: createDirective,
ngModule: ngModule,
}; };
/**
* Return a fake annotation with the basic properties filled in.
*/
function defaultAnnotation() {
return {
id: 'deadbeef',
document: {
title: 'A special document'
},
target: [{}],
uri: 'http://example.com',
user: 'acct:bill@localhost',
updated: '2015-05-10T20:18:56.613388+00:00',
};
}
/** Return an annotation domain model object for a new annotation
* (newly-created client-side, not yet saved to the server).
*/
function newAnnotation() {
return {
id: undefined,
$highlight: undefined,
target: ['foo', 'bar'],
references: [],
text: 'Annotation text',
tags: ['tag_1', 'tag_2']
};
}
/** Return an annotation domain model object for a new highlight
* (newly-created client-side, not yet saved to the server).
*/
function newHighlight() {
return {
id: undefined,
$highlight: true
};
}
/** Return an annotation domain model object for an existing annotation
* received from the server.
*/
function oldAnnotation() {
return {
id: 'annotation_id',
$highlight: undefined,
target: ['foo', 'bar'],
references: [],
text: 'This is my annotation',
tags: ['tag_1', 'tag_2']
};
}
/** Return an annotation domain model object for an existing highlight
* received from the server.
*/
function oldHighlight() {
return {
id: 'annotation_id',
$highlight: undefined,
target: ['foo', 'bar'],
references: [],
text: '',
tags: []
};
}
/** Return an annotation domain model object for an existing page note
* received from the server.
*/
function oldPageNote() {
return {
highlight: undefined,
target: [],
references: [],
text: '',
tags: []
};
}
/** Return an annotation domain model object for an existing reply
* received from the server.
*/
function oldReply() {
return {
highlight: undefined,
target: ['foo'],
references: ['parent_annotation_id'],
text: '',
tags: []
};
}
module.exports = {
defaultAnnotation: defaultAnnotation,
newAnnotation: newAnnotation,
newHighlight: newHighlight,
oldAnnotation: oldAnnotation,
oldHighlight: oldHighlight,
oldPageNote: oldPageNote,
oldReply: oldReply,
};
'use strict';
var annotationMetadata = require('../annotation-metadata');
var extractDocumentMetadata = annotationMetadata.extractDocumentMetadata;
describe('extractDocumentMetadata()', function() {
context('when the model has a document property', function() {
it('returns the hostname from model.uri as the domain', function() {
var model = {
document: {},
uri: 'http://example.com/'
};
assert.equal(extractDocumentMetadata(model).domain, 'example.com');
});
context('when model.uri starts with "urn"', function() {
it(
'uses the first document.link uri that doesn\'t start with "urn"',
function() {
var model = {
uri: 'urn:isbn:0451450523',
document: {
link: [
{href: 'urn:isan:0000-0000-9E59-0000-O-0000-0000-2'},
{href: 'http://example.com/'}
]
}
};
assert.equal(
extractDocumentMetadata(model).uri, 'http://example.com/');
}
);
});
context('when model.uri does not start with "urn"', function() {
it('uses model.uri as the uri', function() {
var model = {
document: {},
uri: 'http://example.com/'
};
assert.equal(
extractDocumentMetadata(model).uri, 'http://example.com/');
});
});
context('when document.title is a string', function() {
it('returns document.title as title', function() {
var model = {
uri: 'http://example.com/',
document: {
title: 'My Document'
}
};
assert.equal(
extractDocumentMetadata(model).title, model.document.title);
});
});
context('when document.title is an array', function() {
it('returns document.title[0] as title', function() {
var model = {
uri: 'http://example.com/',
document: {
title: ['My Document', 'My Other Document']
}
};
assert.equal(
extractDocumentMetadata(model).title, model.document.title[0]);
});
});
context('when there is no document.title', function() {
it('returns the domain as the title', function() {
var model = {
document: {},
uri: 'http://example.com/',
};
assert.equal(extractDocumentMetadata(model).title, 'example.com');
});
});
});
context('when the model does not have a document property', function() {
it('returns model.uri for the uri', function() {
var model = {uri: 'http://example.com/'};
assert.equal(extractDocumentMetadata(model).uri, model.uri);
});
it('returns the hostname of model.uri for the domain', function() {
var model = {uri: 'http://example.com/'};
assert.equal(extractDocumentMetadata(model).domain, 'example.com');
});
it('returns the hostname of model.uri for the title', function() {
var model = {uri: 'http://example.com/'};
assert.equal(extractDocumentMetadata(model).title, 'example.com');
});
});
context('when the title is longer than 30 characters', function() {
it('truncates the title with "…"', function() {
var model = {
uri: 'http://example.com/',
document: {
title: 'My Really Really Long Document Title'
}
};
assert.equal(
extractDocumentMetadata(model).title,
'My Really Really Long Document…'
);
});
});
});
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