Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
0204f7a8
Commit
0204f7a8
authored
Feb 18, 2016
by
Nick Stenning
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2962 from hypothesis/annotation-test-cleanup
Annotation test cleanup
parents
8c2d1df6
aab5355a
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
492 additions
and
661 deletions
+492
-661
annotation-metadata.js
h/static/scripts/annotation-metadata.js
+75
-0
annotation.js
h/static/scripts/directive/annotation.js
+5
-65
annotation-test.js
h/static/scripts/directive/test/annotation-test.js
+152
-593
util.js
h/static/scripts/directive/test/util.js
+31
-3
annotation-fixtures.js
h/static/scripts/test/annotation-fixtures.js
+103
-0
annotation-metadata-test.js
h/static/scripts/test/annotation-metadata-test.js
+126
-0
No files found.
h/static/scripts/annotation-metadata.js
0 → 100644
View file @
0204f7a8
/**
* 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
,
};
h/static/scripts/directive/annotation.js
View file @
0204f7a8
...
...
@@ -3,12 +3,17 @@
var
Promise
=
require
(
'core-js/library/es6/promise'
);
var
annotationMetadata
=
require
(
'../annotation-metadata'
);
var
dateUtil
=
require
(
'../date-util'
);
var
documentDomain
=
require
(
'../filter/document-domain'
);
var
documentTitle
=
require
(
'../filter/document-title'
);
var
events
=
require
(
'../events'
);
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.
*
* domainModel.tags and vm.form.tags use different formats. This
...
...
@@ -43,71 +48,7 @@ function errorMessage(reason) {
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.
*
...
...
@@ -840,7 +781,6 @@ module.exports = {
// to be unit tested.
// FIXME: The code should be refactored to enable unit testing without having
// to do this.
extractDocumentMetadata
:
extractDocumentMetadata
,
link
:
link
,
updateDomainModel
:
updateDomainModel
,
...
...
h/static/scripts/directive/test/annotation-test.js
View file @
0204f7a8
...
...
@@ -5,6 +5,7 @@ var Promise = require('core-js/library/es6/promise');
var
proxyquire
=
require
(
'proxyquire'
);
var
events
=
require
(
'../../events'
);
var
fixtures
=
require
(
'../../test/annotation-fixtures'
);
var
util
=
require
(
'./util'
);
var
module
=
angular
.
mock
.
module
;
...
...
@@ -27,149 +28,7 @@ function annotationDirective() {
return
annotation
.
directive
;
}
/** Return Angular's $compile service. */
function
compileService
()
{
var
$compile
;
inject
(
function
(
_$compile_
)
{
$compile
=
_$compile_
;
});
return
$compile
;
}
/** Return Angular's $document service. */
function
documentService
()
{
var
$document
;
inject
(
function
(
_$document_
)
{
$document
=
_$document_
;
});
return
$document
;
}
describe
(
'annotation'
,
function
()
{
describe
(
'extractDocumentMetadata()'
,
function
()
{
var
extractDocumentMetadata
=
require
(
'../annotation'
)
.
extractDocumentMetadata
;
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…'
);
});
});
});
describe
(
'updateDomainModel()'
,
function
()
{
var
updateDomainModel
=
require
(
'../annotation'
).
updateDomainModel
;
...
...
@@ -275,15 +134,6 @@ describe('annotation', function() {
describe
(
'link'
,
function
()
{
var
link
=
require
(
'../annotation'
).
link
;
/** Return Angular's $rootScope. */
function
getRootScope
()
{
var
$rootScope
;
inject
(
function
(
_$rootScope_
)
{
$rootScope
=
_$rootScope_
;
});
return
$rootScope
;
}
var
scope
;
var
mockElement
;
var
mockAttributes
;
...
...
@@ -294,7 +144,7 @@ describe('annotation', function() {
var
mockControllers
;
beforeEach
(
function
()
{
scope
=
getRootScope
(
).
$new
();
scope
=
util
.
ngModule
(
inject
,
'$rootScope'
).
$new
();
mockElement
=
{
on
:
sinon
.
stub
()};
mockAttributes
=
undefined
;
// Left undefined because link() doesn't use
// it.
...
...
@@ -423,132 +273,34 @@ describe('annotation', function() {
var
$timeout
;
var
$window
;
var
fakeAnnotationMapper
;
var
fakeAnnotationUI
;
var
fakeDocumentDomainFilter
;
var
fakeDocumentTitleFilter
;
var
fakeDrafts
;
var
fakeFeatures
;
var
fakeFlash
;
var
fakeGroups
;
var
fakeMomentFilter
;
var
fakePermissions
;
var
fakePersonaFilter
;
var
fakeSession
;
var
fakeSettings
;
var
fakeTags
;
var
fakeTime
;
var
fakeUrlEncodeFilter
;
var
sandbox
;
function
createDirective
(
annotation
)
{
annotation
=
annotation
||
defaultAnnotation
();
annotation
=
annotation
||
fixtures
.
defaultAnnotation
();
var
element
=
util
.
createDirective
(
document
,
'annotation'
,
{
annotation
:
annotation
,
});
return
{
annotation
:
annotation
,
controller
:
element
.
ctrl
,
element
:
element
,
scope
:
element
.
scope
,
};
}
/** Return the default domain model object that createDirective() uses if
* no custom one is passed to it. */
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
()
{
// A new annotation won't have any saved drafts yet.
if
(
!
annotation
.
id
)
{
fakeDrafts
.
get
.
returns
(
null
);
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
()
{
// A new highlight won't have any saved drafts yet.
fakeDrafts
.
get
.
returns
(
null
);
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
:
[]
annotation
:
annotation
,
controller
:
element
.
ctrl
,
element
:
element
,
scope
:
element
.
scope
,
};
}
/** 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
:
[]
};
}
before
(
function
()
{
angular
.
module
(
'h'
,
[])
...
...
@@ -574,7 +326,7 @@ describe('annotation', function() {
deleteAnnotation
:
sandbox
.
stub
()
};
fakeAnnotationUI
=
{};
var
fakeAnnotationUI
=
{};
fakeDrafts
=
{
update
:
sandbox
.
stub
(),
...
...
@@ -582,14 +334,12 @@ describe('annotation', function() {
get
:
sandbox
.
stub
()
};
fakeFeatures
=
{
var
fakeFeatures
=
{
flagEnabled
:
sandbox
.
stub
().
returns
(
true
)
};
fakeFlash
=
sandbox
.
stub
();
fakeMomentFilter
=
sandbox
.
stub
().
returns
(
'ages ago'
);
fakePermissions
=
{
isShared
:
sandbox
.
stub
().
returns
(
true
),
isPrivate
:
sandbox
.
stub
().
returns
(
false
),
...
...
@@ -612,11 +362,11 @@ describe('annotation', function() {
}
};
fakeSettings
=
{
var
fakeSettings
=
{
serviceUrl
:
'https://test.hypothes.is/'
,
};
fakeTags
=
{
var
fakeTags
=
{
filter
:
sandbox
.
stub
().
returns
(
'a while ago'
),
store
:
sandbox
.
stub
()
};
...
...
@@ -638,7 +388,6 @@ describe('annotation', function() {
$provide
.
value
(
'drafts'
,
fakeDrafts
);
$provide
.
value
(
'features'
,
fakeFeatures
);
$provide
.
value
(
'flash'
,
fakeFlash
);
$provide
.
value
(
'momentFilter'
,
fakeMomentFilter
);
$provide
.
value
(
'permissions'
,
fakePermissions
);
$provide
.
value
(
'session'
,
fakeSession
);
$provide
.
value
(
'settings'
,
fakeSettings
);
...
...
@@ -664,13 +413,13 @@ describe('annotation', function() {
sandbox
.
restore
();
});
describe
(
'
AnnotationController()
initialization'
,
function
()
{
describe
(
'initialization'
,
function
()
{
it
(
'sets the user of annotations that don
\'
t have one'
,
function
()
{
// You can create annotations while logged out and then login.
// When you login a new AnnotationController instance is created for
// each of your annotations, and on initialization it will set the
// annotation's user to your username from the session.
var
annotation
=
newAnnotation
();
var
annotation
=
fixtures
.
newAnnotation
();
annotation
.
user
=
undefined
;
fakeSession
.
state
.
userid
=
'acct:bill@localhost'
;
...
...
@@ -679,26 +428,48 @@ describe('annotation', function() {
assert
.
equal
(
annotation
.
user
,
'acct:bill@localhost'
);
});
it
(
'sets the permissions of annotations that don
\'
t have any'
,
function
()
{
it
(
'sets the permissions of new annotations'
,
function
()
{
// You can create annotations while logged out and then login.
// When you login a new AnnotationController instance is created for
// each of your annotations, and on initialization it will set the
// annotation's permissions using your username from the session.
var
annotation
=
newAnnotation
();
var
annotation
=
fixtures
.
newAnnotation
();
annotation
.
user
=
annotation
.
permissions
=
undefined
;
annotation
.
group
=
'__world__'
;
fakeSession
.
state
.
userid
=
'acct:bill@localhost'
;
fakePermissions
.
default
.
returns
(
'default permissions'
);
fakePermissions
.
default
=
function
(
group
)
{
return
'default permissions for '
+
group
;
};
createDirective
(
annotation
);
assert
.
equal
(
annotation
.
permissions
,
'default permissions'
);
assert
.
equal
(
annotation
.
permissions
,
'default permissions for __world__'
);
});
it
(
'preserves the permissions of existing annotations'
,
function
()
{
var
annotation
=
fixtures
.
newAnnotation
();
annotation
.
permissions
=
{
permissions
:
{
read
:
[
'foo'
],
update
:
[
'bar'
],
'delete'
:
[
'gar'
],
admin
:
[
'har'
]
}
);
};
var
originalPermissions
=
JSON
.
parse
(
JSON
.
stringify
(
annotation
.
permissions
));
fakePermissions
[
'default'
]
=
function
()
{
return
'new permissions'
;
};
fakePermissions
.
isShared
=
function
()
{};
fakePermissions
.
isPrivate
=
function
()
{};
createDirective
(
annotation
);
assert
.
deepEqual
(
annotation
.
permissions
,
originalPermissions
);
});
it
(
'saves new highlights to the server on initialization'
,
function
()
{
var
annotation
=
newHighlight
();
var
annotation
=
fixtures
.
newHighlight
();
// The user is logged-in.
annotation
.
user
=
fakeSession
.
state
.
userid
=
'acct:bill@localhost'
;
annotation
.
$create
=
sandbox
.
stub
().
returns
({
...
...
@@ -711,7 +482,7 @@ describe('annotation', function() {
});
it
(
'saves new highlights to drafts if not logged in'
,
function
()
{
var
annotation
=
newHighlight
();
var
annotation
=
fixtures
.
newHighlight
();
// The user is not logged-in.
annotation
.
user
=
fakeSession
.
state
.
userid
=
undefined
;
annotation
.
$create
=
sandbox
.
stub
().
returns
({
...
...
@@ -725,7 +496,7 @@ describe('annotation', function() {
});
it
(
'does not save new annotations on initialization'
,
function
()
{
var
annotation
=
newAnnotation
();
var
annotation
=
fixtures
.
newAnnotation
();
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
});
...
...
@@ -736,7 +507,7 @@ describe('annotation', function() {
});
it
(
'does not save old highlights on initialization'
,
function
()
{
var
annotation
=
oldHighlight
();
var
annotation
=
fixtures
.
oldHighlight
();
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
});
...
...
@@ -747,7 +518,7 @@ describe('annotation', function() {
});
it
(
'does not save old annotations on initialization'
,
function
()
{
var
annotation
=
oldAnnotation
();
var
annotation
=
fixtures
.
oldAnnotation
();
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
});
...
...
@@ -758,7 +529,7 @@ describe('annotation', function() {
});
it
(
'edits new annotations on initialization'
,
function
()
{
var
annotation
=
newAnnotation
();
var
annotation
=
fixtures
.
newAnnotation
();
var
controller
=
createDirective
(
annotation
).
controller
;
...
...
@@ -766,7 +537,7 @@ describe('annotation', function() {
});
it
(
'edits annotations with drafts on initialization'
,
function
()
{
var
annotation
=
oldAnnotation
();
var
annotation
=
fixtures
.
oldAnnotation
();
// The drafts service has some draft changes for this annotation.
fakeDrafts
.
get
.
returns
(
'foo'
);
...
...
@@ -776,7 +547,7 @@ describe('annotation', function() {
});
it
(
'does not edit new highlights on initialization'
,
function
()
{
var
annotation
=
newHighlight
();
var
annotation
=
fixtures
.
newHighlight
();
// We have to set annotation.$create() because it'll try to call it.
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
...
...
@@ -788,7 +559,7 @@ describe('annotation', function() {
});
it
(
'edits highlights with drafts on initialization'
,
function
()
{
var
annotation
=
oldHighlight
();
var
annotation
=
fixtures
.
oldHighlight
();
// You can edit a highlight, enter some text or tags, and save it (the
// highlight then becomes an annotation). You can also edit a highlight
// and then change focus to another group and back without saving the
...
...
@@ -802,7 +573,7 @@ describe('annotation', function() {
});
});
describe
(
'
AnnotationController
.editing()'
,
function
()
{
describe
(
'.editing()'
,
function
()
{
it
(
'returns true if action is "create"'
,
function
()
{
var
controller
=
createDirective
().
controller
;
controller
.
action
=
'create'
;
...
...
@@ -822,9 +593,9 @@ describe('annotation', function() {
});
});
describe
(
'
AnnotationController
.isHighlight()'
,
function
()
{
describe
(
'.isHighlight()'
,
function
()
{
it
(
'returns true for new highlights'
,
function
()
{
var
annotation
=
newHighlight
();
var
annotation
=
fixtures
.
newHighlight
();
// We need to define $create because it'll try to call it.
annotation
.
$create
=
function
()
{
return
{
then
:
function
()
{}};};
...
...
@@ -834,7 +605,7 @@ describe('annotation', function() {
});
it
(
'returns false for new annotations'
,
function
()
{
var
annotation
=
newAnnotation
();
var
annotation
=
fixtures
.
newAnnotation
();
var
vm
=
createDirective
(
annotation
).
controller
;
...
...
@@ -842,7 +613,7 @@ describe('annotation', function() {
});
it
(
'returns false for page notes'
,
function
()
{
var
annotation
=
oldPageNote
();
var
annotation
=
fixtures
.
oldPageNote
();
var
vm
=
createDirective
(
annotation
).
controller
;
...
...
@@ -850,7 +621,7 @@ describe('annotation', function() {
});
it
(
'returns false for replies'
,
function
()
{
var
annotation
=
oldReply
();
var
annotation
=
fixtures
.
oldReply
();
var
vm
=
createDirective
(
annotation
).
controller
;
...
...
@@ -858,7 +629,7 @@ describe('annotation', function() {
});
it
(
'returns false for annotations with text but no tags'
,
function
()
{
var
annotation
=
oldAnnotation
();
var
annotation
=
fixtures
.
oldAnnotation
();
annotation
.
text
=
'This is my annotation'
;
annotation
.
tags
=
[];
...
...
@@ -868,7 +639,7 @@ describe('annotation', function() {
});
it
(
'returns false for annotations with tags but no text'
,
function
()
{
var
annotation
=
oldAnnotation
();
var
annotation
=
fixtures
.
oldAnnotation
();
annotation
.
text
=
''
;
annotation
.
tags
=
[
'foo'
];
...
...
@@ -878,7 +649,7 @@ describe('annotation', function() {
});
it
(
'returns true for annotations with no text or tags'
,
function
()
{
var
annotation
=
oldAnnotation
();
var
annotation
=
fixtures
.
oldAnnotation
();
annotation
.
text
=
''
;
annotation
.
tags
=
[];
...
...
@@ -892,7 +663,7 @@ describe('annotation', function() {
var
annotation
;
beforeEach
(
function
()
{
annotation
=
defaultAnnotation
();
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
$highlight
=
true
;
annotation
.
$create
=
sinon
.
stub
().
returns
({
then
:
angular
.
noop
,
...
...
@@ -915,7 +686,7 @@ describe('annotation', function() {
var
annotation
;
beforeEach
(
function
()
{
annotation
=
defaultAnnotation
();
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
permissions
=
{
read
:
[
'acct:joe@localhost'
],
update
:
[
'acct:joe@localhost'
],
...
...
@@ -946,7 +717,7 @@ describe('annotation', function() {
});
it
(
'makes the annotation shared if the parent is shared'
,
function
()
{
var
annotation
=
defaultAnnotation
();
var
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
group
=
'my group'
;
annotation
.
permissions
=
{
read
:
[
'my-group'
],
...
...
@@ -981,7 +752,7 @@ describe('annotation', function() {
);
it
(
'sets the reply
\'
s group to be the same as its parent
\'
s'
,
function
()
{
var
annotation
=
defaultAnnotation
();
var
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
group
=
'my group'
;
var
controller
=
createDirective
(
annotation
).
controller
;
var
reply
=
{};
...
...
@@ -1082,7 +853,7 @@ describe('annotation', function() {
describe
(
'#hasQuotes'
,
function
()
{
it
(
'returns false if the annotation has no quotes'
,
function
()
{
var
annotation
=
defaultAnnotation
();
var
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
target
=
[{}];
var
controller
=
createDirective
(
annotation
).
controller
;
...
...
@@ -1090,7 +861,7 @@ describe('annotation', function() {
});
it
(
'returns true if the annotation has quotes'
,
function
()
{
var
annotation
=
defaultAnnotation
();
var
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
target
=
[
{
selector
:
[
...
...
@@ -1112,7 +883,7 @@ describe('annotation', function() {
beforeEach
(
function
()
{
clock
=
sinon
.
useFakeTimers
();
annotation
=
defaultAnnotation
();
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
created
=
(
new
Date
()).
toString
();
annotation
.
updated
=
(
new
Date
()).
toString
();
});
...
...
@@ -1206,7 +977,7 @@ describe('annotation', function() {
describe
(
'absoluteTimestamp'
,
function
()
{
it
(
'returns the current time'
,
function
()
{
var
annotation
=
defaultAnnotation
();
var
annotation
=
fixtures
.
defaultAnnotation
();
var
controller
=
createDirective
(
annotation
).
controller
;
var
expectedDate
=
new
Date
(
annotation
.
updated
);
// the exact format of the result will depend on the current locale,
...
...
@@ -1223,7 +994,7 @@ describe('annotation', function() {
dialog
.
find
(
'button'
).
click
();
parts
.
scope
.
$digest
();
assert
.
ok
(
dialog
.
hasClass
(
'open'
));
documentService
(
).
click
();
util
.
ngModule
(
inject
,
'$document'
).
click
();
assert
.
notOk
(
dialog
.
hasClass
(
'open'
));
});
});
...
...
@@ -1309,7 +1080,7 @@ describe('annotation', function() {
beforeEach
(
function
()
{
fakeFlash
.
error
=
sandbox
.
stub
();
annotation
=
defaultAnnotation
();
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
$create
=
sandbox
.
stub
();
});
...
...
@@ -1404,6 +1175,26 @@ describe('annotation', function() {
assert
.
ok
(
controller
.
editing
());
});
});
it
(
'Passes group:<id> to the server when saving a new annotation'
,
function
()
{
fakeGroups
.
focused
=
function
()
{
return
{
id
:
'test-id'
}
};
var
annotation
=
{
user
:
'acct:fred@hypothes.is'
,
text
:
'foo'
,
};
annotation
.
$create
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
var
controller
=
createDirective
(
annotation
).
controller
;
controller
.
action
=
'create'
;
return
controller
.
save
().
then
(
function
()
{
assert
.
equal
(
annotation
.
$create
.
lastCall
.
thisValue
.
group
,
'test-id'
);
});
}
);
});
describe
(
'saving an edited an annotation'
,
function
()
{
...
...
@@ -1411,7 +1202,7 @@ describe('annotation', function() {
beforeEach
(
function
()
{
fakeFlash
.
error
=
sandbox
.
stub
();
annotation
=
defaultAnnotation
();
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
$update
=
sandbox
.
stub
();
});
...
...
@@ -1500,7 +1291,7 @@ describe('annotation', function() {
});
it
(
'removes the draft when changes are saved'
,
function
()
{
var
annotation
=
defaultAnnotation
();
var
annotation
=
fixtures
.
defaultAnnotation
();
annotation
.
$update
=
sandbox
.
stub
().
returns
(
Promise
.
resolve
());
var
controller
=
createDirective
(
annotation
).
controller
;
controller
.
edit
();
...
...
@@ -1570,7 +1361,7 @@ describe('annotation', function() {
);
it
(
'updates domainModel.group if the annotation is new'
,
function
()
{
var
annotation
=
newAnnotation
();
var
annotation
=
fixtures
.
newAnnotation
();
annotation
.
group
=
'old-group-id'
;
createDirective
(
annotation
);
fakeGroups
.
focused
=
sandbox
.
stub
().
returns
({
id
:
'new-group-id'
});
...
...
@@ -1582,7 +1373,7 @@ describe('annotation', function() {
it
(
'does not update domainModel.group if the annotation is not new'
,
function
()
{
var
annotation
=
oldAnnotation
();
var
annotation
=
fixtures
.
oldAnnotation
();
annotation
.
group
=
'old-group-id'
;
createDirective
(
annotation
);
fakeGroups
.
focused
=
sandbox
.
stub
().
returns
({
id
:
'new-group-id'
});
...
...
@@ -1593,243 +1384,15 @@ describe('annotation', function() {
}
);
});
});
describe
(
'AnnotationController'
,
function
()
{
before
(
function
()
{
angular
.
module
(
'h'
,
[])
.
directive
(
'annotation'
,
annotationDirective
());
});
beforeEach
(
module
(
'h'
));
beforeEach
(
module
(
'h.templates'
));
/** Return Angular's $rootScope. */
function
getRootScope
()
{
var
$rootScope
;
inject
(
function
(
_$rootScope_
)
{
$rootScope
=
_$rootScope_
;
});
return
$rootScope
;
}
/**
Return an annotation directive instance and stub services etc.
*/
function
createAnnotationDirective
(
args
)
{
var
session
=
args
.
session
||
{
state
:
{
userid
:
'acct:fred@hypothes.is'
}
};
var
locals
=
{
personaFilter
:
args
.
personaFilter
||
function
()
{},
momentFilter
:
args
.
momentFilter
||
{},
urlencodeFilter
:
args
.
urlencodeFilter
||
{},
drafts
:
args
.
drafts
||
{
update
:
function
()
{},
remove
:
function
()
{},
get
:
function
()
{}
},
features
:
args
.
features
||
{
flagEnabled
:
function
()
{
return
true
;
}
},
flash
:
args
.
flash
||
{
info
:
function
()
{},
error
:
function
()
{}
},
permissions
:
args
.
permissions
||
{
isShared
:
function
(
permissions
,
group
)
{
if
(
permissions
.
read
)
{
return
permissions
.
read
.
indexOf
(
group
)
!==
-
1
;
}
else
{
return
false
;
}
},
isPrivate
:
function
(
permissions
,
user
)
{
if
(
permissions
.
read
)
{
return
permissions
.
read
.
indexOf
(
user
)
!==
-
1
;
}
else
{
return
false
;
}
},
permits
:
function
()
{
return
true
;
},
shared
:
function
()
{
return
{};
},
'private'
:
function
()
{
return
{};
},
'default'
:
function
()
{
return
{};
},
setDefault
:
function
()
{}
},
session
:
session
,
settings
:
{
serviceUrl
:
'https://test.hypothes.is/'
},
tags
:
args
.
tags
||
{
store
:
function
()
{}
},
time
:
args
.
time
||
{
toFuzzyString
:
function
()
{},
decayingInterval
:
function
()
{}
},
annotationUI
:
args
.
annotationUI
||
{},
annotationMapper
:
args
.
annotationMapper
||
{},
groups
:
args
.
groups
||
{
get
:
function
()
{},
focused
:
function
()
{
return
{};
}
},
documentTitleFilter
:
args
.
documentTitleFilter
||
function
()
{
return
''
;
},
documentDomainFilter
:
args
.
documentDomainFilter
||
function
()
{
return
''
;
},
localStorage
:
args
.
localStorage
||
{
setItem
:
function
()
{},
getItem
:
function
()
{}
}
};
module
(
function
(
$provide
)
{
$provide
.
value
(
'personaFilter'
,
locals
.
personaFilter
);
$provide
.
value
(
'momentFilter'
,
locals
.
momentFilter
);
$provide
.
value
(
'urlencodeFilter'
,
locals
.
urlencodeFilter
);
$provide
.
value
(
'drafts'
,
locals
.
drafts
);
$provide
.
value
(
'features'
,
locals
.
features
);
$provide
.
value
(
'flash'
,
locals
.
flash
);
$provide
.
value
(
'permissions'
,
locals
.
permissions
);
$provide
.
value
(
'session'
,
locals
.
session
);
$provide
.
value
(
'settings'
,
locals
.
settings
);
$provide
.
value
(
'tags'
,
locals
.
tags
);
$provide
.
value
(
'time'
,
locals
.
time
);
$provide
.
value
(
'annotationUI'
,
locals
.
annotationUI
);
$provide
.
value
(
'annotationMapper'
,
locals
.
annotationMapper
);
$provide
.
value
(
'groups'
,
locals
.
groups
);
$provide
.
value
(
'documentTitleFilter'
,
locals
.
documentTitleFilter
);
$provide
.
value
(
'documentDomainFilter'
,
locals
.
documentDomainFilter
);
$provide
.
value
(
'localStorage'
,
locals
.
localStorage
);
});
locals
.
element
=
angular
.
element
(
'<annotation annotation="annotation">'
);
var
compiledElement
=
compileService
()(
locals
.
element
);
locals
.
$rootScope
=
getRootScope
();
locals
.
parentScope
=
locals
.
$rootScope
.
$new
();
locals
.
parentScope
.
annotation
=
args
.
annotation
||
{};
locals
.
directive
=
compiledElement
(
locals
.
parentScope
);
locals
.
$rootScope
.
$digest
();
locals
.
controller
=
locals
.
element
.
controller
(
'annotation'
);
locals
.
isolateScope
=
locals
.
element
.
isolateScope
();
return
locals
;
}
describe
(
'createAnnotationDirective'
,
function
()
{
it
(
'creates the directive without crashing'
,
function
()
{
createAnnotationDirective
({});
});
});
it
(
'sets the user of new annotations'
,
function
()
{
var
annotation
=
{};
var
session
=
createAnnotationDirective
({
annotation
:
annotation
}).
session
;
assert
.
equal
(
annotation
.
user
,
session
.
state
.
userid
);
});
it
(
'sets the permissions of new annotations'
,
function
()
{
// This is a new annotation, doesn't have any permissions yet.
var
annotation
=
{
group
:
'test-group'
};
var
permissions
=
{
'default'
:
sinon
.
stub
().
returns
(
'default permissions'
),
isShared
:
function
()
{},
isPrivate
:
function
()
{}
};
createAnnotationDirective
({
annotation
:
annotation
,
permissions
:
permissions
});
assert
(
permissions
[
'default'
].
calledWithExactly
(
'test-group'
));
assert
.
equal
(
annotation
.
permissions
,
'default permissions'
,
'It should set a new annotation
\'
s permissions to what '
+
'permissions.default() returns'
);
});
it
(
'doesn
\'
t overwrite permissions if the annotation already has them'
,
function
()
{
var
annotation
=
{
permissions
:
{
read
:
[
'foo'
],
update
:
[
'bar'
],
'delete'
:
[
'gar'
],
admin
:
[
'har'
]
}
};
var
originalPermissions
=
JSON
.
parse
(
JSON
.
stringify
(
annotation
.
permissions
));
var
permissions
=
{
'default'
:
sinon
.
stub
().
returns
(
'new permissions'
),
isShared
:
function
()
{},
isPrivate
:
function
()
{}
};
createAnnotationDirective
({
annotation
:
annotation
,
permissions
:
permissions
});
assert
.
deepEqual
(
annotation
.
permissions
,
originalPermissions
);
}
);
describe
(
'save'
,
function
()
{
it
(
'Passes group:<id> to the server when saving a new annotation'
,
function
()
{
var
annotation
=
{
user
:
'acct:fred@hypothes.is'
,
text
:
'foo'
};
annotation
.
$create
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
var
group
=
{
id
:
'test-id'
};
var
controller
=
createAnnotationDirective
({
annotation
:
annotation
,
groups
:
{
focused
:
function
()
{
return
group
;
},
get
:
function
()
{}
}
}).
controller
;
controller
.
action
=
'create'
;
return
controller
.
save
().
then
(
function
()
{
assert
(
annotation
.
$create
.
lastCall
.
thisValue
.
group
===
'test-id'
);
});
}
);
});
/*
Simulate what happens when the user edits an annotation, clicks Save,
gets an error because the server fails to save the annotation, then clicks
Cancel - in the frontend the annotation should be restored to its original
value, the edits lost.
*/
it
(
'restores the original text when editing is cancelled'
,
function
()
{
var
controller
=
createAnnotationDirective
({
annotation
:
{
describe
(
'reverting edits'
,
function
()
{
// Simulate what happens when the user edits an annotation,
// clicks Save, gets an error because the server fails to save the
// annotation, then clicks Cancel - in the frontend the annotation should
// be restored to its original value, the edits lost.
it
(
'restores the original text'
,
function
()
{
var
controller
=
createDirective
({
id
:
'test-annotation-id'
,
user
:
'acct:bill@localhost'
,
text
:
'Initial annotation body text'
,
...
...
@@ -1845,7 +1408,6 @@ describe('annotation', function() {
data
:
{}
});
}
}
}).
controller
;
var
originalText
=
controller
.
form
.
text
;
// Simulate the user clicking the Edit button on the annotation.
...
...
@@ -1863,14 +1425,12 @@ describe('annotation', function() {
assert
(
controller
.
form
.
text
===
originalText
);
});
// t
est that editing reverting changes to an annotation with
// T
est that editing reverting changes to an annotation with
// no text resets the text to be empty.
it
(
'clears the text when reverting changes to a highlight'
,
function
()
{
var
controller
=
createAnnotationDirective
({
annotation
:
{
it
(
'clears the text if the text was originally empty'
,
function
()
{
var
controller
=
createDirective
({
id
:
'test-annotation-id'
,
user
:
'acct:bill@localhost'
,
}
}).
controller
;
controller
.
edit
();
assert
.
equal
(
controller
.
action
,
'edit'
);
...
...
@@ -1879,11 +1439,10 @@ describe('annotation', function() {
assert
.
equal
(
controller
.
form
.
text
,
void
0
);
});
it
(
'reverts to the most recently saved version when canceling changes
'
,
it
(
'reverts to the most recently saved version
'
,
function
()
{
var
controller
=
createAnnotationDirective
({
annotation
:
{
var
controller
=
createDirective
({
user
:
'acct:bill@localhost'
,
$create
:
function
()
{
this
.
id
=
'new-annotation-id'
;
...
...
@@ -1892,7 +1451,6 @@ describe('annotation', function() {
$update
:
function
()
{
return
Promise
.
resolve
(
this
);
},
},
}).
controller
;
controller
.
edit
();
controller
.
form
.
text
=
'New annotation text'
;
...
...
@@ -1907,4 +1465,5 @@ describe('annotation', function() {
});
});
});
});
});
h/static/scripts/directive/test/util.js
View file @
0204f7a8
'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
)
{
var
uppercasePattern
=
/
([
A-Z
])
/g
;
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.
*
...
...
@@ -124,5 +151,6 @@ function createDirective(document, name, attrs, initialScope, initialHtml, opts)
}
module
.
exports
=
{
createDirective
:
createDirective
createDirective
:
createDirective
,
ngModule
:
ngModule
,
};
h/static/scripts/test/annotation-fixtures.js
0 → 100644
View file @
0204f7a8
/**
* 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
,
};
h/static/scripts/test/annotation-metadata-test.js
0 → 100644
View file @
0204f7a8
'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…'
);
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment