2015-06-04 04:47:58 +00:00
new function ( ) {
2015-04-26 06:44:29 +00:00
Components . utils . import ( "resource://gre/modules/osfile.jsm" ) ;
2019-01-26 05:11:27 +00:00
Components . utils . import ( "resource://zotero-unit/httpd.js" ) ;
2015-04-26 06:44:29 +00:00
2023-04-14 15:37:07 +00:00
const { HiddenBrowser } = ChromeUtils . import ( 'chrome://zotero/content/HiddenBrowser.jsm' ) ;
2015-06-04 04:47:58 +00:00
/ * *
* Create a new translator that saves the specified items
* @ param { String } translatorType - "import" or "web"
* @ param { Object } items - items as translator JSON
* /
2019-01-08 07:07:15 +00:00
function saveItemsThroughTranslator ( translatorType , items , translateOptions = { } ) {
2015-06-04 04:47:58 +00:00
let tyname ;
if ( translatorType == "web" ) {
tyname = "Web" ;
} else if ( translatorType == "import" ) {
tyname = "Import" ;
} else {
throw new Error ( "invalid translator type " + translatorType ) ;
}
let translate = new Zotero . Translate [ tyname ] ( ) ;
if ( translatorType == "web" ) {
2023-04-14 15:37:07 +00:00
let doc = new DOMParser ( ) . parseFromString ( '<!DOCTYPE html><html></html>' , 'text/html' ) ;
doc = Zotero . HTTP . wrapDocument ( doc , 'https://www.example.com/' ) ;
translate . setDocument ( doc ) ;
2015-06-04 04:47:58 +00:00
} else if ( translatorType == "import" ) {
translate . setString ( "" ) ;
}
2016-11-23 00:06:47 +00:00
translate . setTranslator ( buildDummyTranslator (
translatorType ,
2015-06-04 04:47:58 +00:00
"function detectWeb() {}\n" +
"function do" + tyname + "() {\n" +
2015-09-17 17:58:19 +00:00
" var json = JSON.parse('" + JSON . stringify ( items ) . replace ( /['\\]/g , "\\$&" ) + "');\n" +
2015-06-04 04:47:58 +00:00
" for (var i=0; i<json.length; i++) {" +
" var item = new Zotero.Item;\n" +
" for (var field in json[i]) { item[field] = json[i][field]; }\n" +
" item.complete();\n" +
" }\n" +
"}" ) ) ;
2019-01-08 07:07:15 +00:00
return translate . translate ( translateOptions ) . then ( function ( items ) {
2015-06-04 04:47:58 +00:00
return items ;
} ) ;
}
/ * *
* Convert an array of items to an object in which they are indexed by
* their display titles
* /
2016-03-11 09:50:55 +00:00
function itemsArrayToObject ( items ) {
2015-06-04 04:47:58 +00:00
var obj = { } ;
for ( let item of items ) {
2016-03-11 09:50:55 +00:00
obj [ item . getDisplayTitle ( ) ] = item ;
2015-06-04 04:47:58 +00:00
}
return obj ;
2016-03-11 09:50:55 +00:00
}
2015-06-04 04:47:58 +00:00
const TEST _TAGS = [
"manual tag as string" ,
{ "tag" : "manual tag as object" } ,
{ "tag" : "manual tag as object with type" , "type" : 0 } ,
{ "tag" : "automatic tag as object" , "type" : 1 } ,
2021-12-19 08:01:17 +00:00
{ "name" : "tag in name property" } ,
{ name : "" } ,
{ name : " " } ,
2015-06-04 04:47:58 +00:00
] ;
/ * *
* Check that tags match expected values , if TEST _TAGS is passed as test array
* /
function checkTestTags ( newItem , web ) {
assert . equal ( newItem . getTagType ( "manual tag as string" ) , web ? 1 : 0 ) ;
assert . equal ( newItem . getTagType ( "manual tag as object" ) , web ? 1 : 0 ) ;
assert . equal ( newItem . getTagType ( "manual tag as object with type" ) , web ? 1 : 0 ) ;
assert . equal ( newItem . getTagType ( "automatic tag as object" ) , 1 ) ;
assert . equal ( newItem . getTagType ( "tag in name property" ) , web ? 1 : 0 ) ;
}
/ * *
* Get included test snapshot file
* @ returns { nsIFile }
* /
function getTestSnapshot ( ) {
let snapshot = getTestDataDirectory ( ) ;
snapshot . append ( "snapshot" ) ;
snapshot . append ( "index.html" ) ;
return snapshot ;
}
/ * *
* Get included test snapshot file
* @ returns { nsIFile }
* /
function getTestPDF ( ) {
let testPDF = getTestDataDirectory ( ) ;
testPDF . append ( "empty.pdf" ) ;
return testPDF ;
}
/ * *
* Set up endpoints for testing attachment saving
* This must happen immediately before the test , since Zotero might get
* restarted by resetDB ( ) , which would erase our registered endpoints .
* /
function setupAttachmentEndpoints ( ) {
var SnapshotTest = function ( ) { } ;
Zotero . Server . Endpoints [ "/test/translate/test.html" ] = SnapshotTest ;
SnapshotTest . prototype = {
"supportedMethods" : [ "GET" ] ,
"init" : function ( data , sendResponseCallback ) {
Zotero . File . getBinaryContentsAsync ( getTestSnapshot ( ) ) . then ( function ( data ) {
sendResponseCallback ( 200 , "text/html" , data ) ;
} ) ;
}
}
var PDFTest = function ( ) { } ;
Zotero . Server . Endpoints [ "/test/translate/test.pdf" ] = PDFTest ;
PDFTest . prototype = {
"supportedMethods" : [ "GET" ] ,
"init" : function ( data , sendResponseCallback ) {
Zotero . File . getBinaryContentsAsync ( getTestPDF ( ) ) . then ( function ( data ) {
sendResponseCallback ( 200 , "application/pdf" , data ) ;
} ) ;
}
}
var NonExistentTest = function ( ) { } ;
Zotero . Server . Endpoints [ "/test/translate/does_not_exist.html" ] = NonExistentTest ;
NonExistentTest . prototype = {
"supportedMethods" : [ "GET" ] ,
"init" : function ( data , sendResponseCallback ) {
sendResponseCallback ( 404 , "text/html" , "File does not exist" ) ;
}
}
}
2021-11-06 03:12:37 +00:00
/ * *
* Set up endpoints for testing async translators
* As above , this must happen immediately before the test .
* /
function setupAsyncEndpoints ( ) {
var JSONTest = function ( ) { } ;
Zotero . Server . Endpoints [ "/test/translate/test.json" ] = JSONTest ;
JSONTest . prototype = {
"supportedMethods" : [ "GET" ] ,
"init" : function ( data , sendResponseCallback ) {
sendResponseCallback ( 200 , "application/json" , JSON . stringify ( {
success : true ,
array : [ 1 , 2 , 3 ]
} ) ) ;
}
}
}
2015-06-04 04:47:58 +00:00
describe ( "Zotero.Translate" , function ( ) {
let win ;
before ( function * ( ) {
2016-08-25 16:41:18 +00:00
// TEMP: Fix for slow translator initialization on Linux/Travis
this . timeout ( 20000 ) ;
yield Zotero . Translators . init ( ) ;
2015-06-04 04:47:58 +00:00
setupAttachmentEndpoints ( ) ;
win = yield loadBrowserWindow ( ) ;
} ) ;
after ( function ( ) {
win . close ( ) ;
} ) ;
describe ( "Zotero.Item" , function ( ) {
it ( 'should save ordinary fields and creators' , function * ( ) {
2015-06-11 06:19:49 +00:00
this . timeout ( 10000 ) ;
2015-06-04 04:47:58 +00:00
let data = loadSampleData ( 'allTypesAndFields' ) ;
let trueItems = loadSampleData ( 'itemJSON' ) ;
let saveItems = [ ] ;
for ( let itemType in data ) {
saveItems . push ( data [ itemType ] ) ;
let trueItem = trueItems [ itemType ] ;
delete trueItem . dateAdded ;
delete trueItem . dateModified ;
delete trueItem . key ;
}
let newItems = yield saveItemsThroughTranslator ( "import" , saveItems ) ;
let savedItems = { } ;
for ( let i = 0 ; i < newItems . length ; i ++ ) {
Deasyncification :back: :cry:
While trying to get translation and citing working with asynchronously
generated data, we realized that drag-and-drop support was going to
be...problematic. Firefox only supports synchronous methods for
providing drag data (unlike, it seems, the DataTransferItem interface
supported by Chrome), which means that we'd need to preload all relevant
data on item selection (bounded by export.quickCopy.dragLimit) and keep
the translate/cite methods synchronous (or maintain two separate
versions).
What we're trying instead is doing what I said in #518 we weren't going
to do: loading most object data on startup and leaving many more
functions synchronous. Essentially, this takes the various load*()
methods described in #518, moves them to startup, and makes them operate
on entire libraries rather than individual objects.
The obvious downside here (other than undoing much of the work of the
last many months) is that it increases startup time, potentially quite a
lot for larger libraries. On my laptop, with a 3,000-item library, this
adds about 3 seconds to startup time. I haven't yet tested with larger
libraries. But I'm hoping that we can optimize this further to reduce
that delay. Among other things, this is loading data for all libraries,
when it should be able to load data only for the library being viewed.
But this is also fundamentally just doing some SELECT queries and
storing the results, so it really shouldn't need to be that slow (though
performance may be bounded a bit here by XPCOM overhead).
If we can make this fast enough, it means that third-party plugins
should be able to remain much closer to their current designs. (Some
things, including saving, will still need to be made asynchronous.)
2016-03-07 21:05:51 +00:00
let savedItem = newItems [ i ] . toJSON ( ) ;
2015-06-04 04:47:58 +00:00
savedItems [ Zotero . ItemTypes . getName ( newItems [ i ] . itemTypeID ) ] = savedItem ;
delete savedItem . dateAdded ;
delete savedItem . dateModified ;
delete savedItem . key ;
}
assert . deepEqual ( savedItems , trueItems , "saved items match inputs" ) ;
} ) ;
2015-06-07 22:38:00 +00:00
it ( 'should accept deprecated SQL accessDates' , function * ( ) {
let myItem = {
"itemType" : "webpage" ,
"title" : "Test Item" ,
"accessDate" : "2015-01-02 03:04:05"
}
let newItems = yield saveItemsThroughTranslator ( "import" , [ myItem ] ) ;
assert . equal ( newItems [ 0 ] . getField ( "accessDate" ) , "2015-01-02 03:04:05" ) ;
} ) ;
2015-06-04 04:47:58 +00:00
it ( 'should save tags' , function * ( ) {
let myItem = {
"itemType" : "book" ,
"title" : "Test Item" ,
"tags" : TEST _TAGS
} ;
checkTestTags ( ( yield saveItemsThroughTranslator ( "import" , [ myItem ] ) ) [ 0 ] ) ;
} ) ;
it ( 'should save notes' , function * ( ) {
let myItems = [
{
"itemType" : "book" ,
"title" : "Test Item" ,
"notes" : [
"1 note as string" ,
{
"note" : "2 note as object" ,
"tags" : TEST _TAGS
}
]
} ,
{
"itemType" : "note" ,
"note" : "standalone note" ,
"tags" : TEST _TAGS
}
] ;
2016-03-11 09:50:55 +00:00
let newItems = itemsArrayToObject ( yield saveItemsThroughTranslator ( "import" , myItems ) ) ;
2015-06-04 04:47:58 +00:00
let noteIDs = newItems [ "Test Item" ] . getNotes ( ) ;
let note1 = yield Zotero . Items . getAsync ( noteIDs [ 0 ] ) ;
assert . equal ( Zotero . ItemTypes . getName ( note1 . itemTypeID ) , "note" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( note1 . note , "1 note as string" ) ;
2015-06-04 04:47:58 +00:00
let note2 = yield Zotero . Items . getAsync ( noteIDs [ 1 ] ) ;
assert . equal ( Zotero . ItemTypes . getName ( note2 . itemTypeID ) , "note" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( note2 . note , "2 note as object" ) ;
2015-06-04 04:47:58 +00:00
checkTestTags ( note2 ) ;
let note3 = newItems [ "standalone note" ] ;
2020-08-25 18:22:23 +00:00
assert . equal ( note3 . note , "standalone note" ) ;
2015-06-04 04:47:58 +00:00
checkTestTags ( note3 ) ;
} ) ;
2017-09-22 05:02:50 +00:00
it ( 'should save relations' , async function ( ) {
var item = await createDataObject ( 'item' ) ;
var itemURI = Zotero . URI . getItemURI ( item ) ;
let myItem = {
itemType : "book" ,
title : "Test Item" ,
relations : {
"dc:relation" : [ itemURI ]
}
} ;
let newItems = await saveItemsThroughTranslator ( "import" , [ myItem ] ) ;
var relations = newItems [ 0 ] . getRelations ( ) ;
assert . lengthOf ( Object . keys ( relations ) , 1 ) ;
assert . lengthOf ( relations [ "dc:relation" ] , 1 ) ;
assert . equal ( relations [ "dc:relation" ] [ 0 ] , itemURI ) ;
} ) ;
2015-06-04 04:47:58 +00:00
it ( 'should save collections' , function * ( ) {
let translate = new Zotero . Translate . Import ( ) ;
translate . setString ( "" ) ;
translate . setTranslator ( buildDummyTranslator ( 4 ,
'function detectWeb() {}\n' +
'function doImport() {\n' +
' var item1 = new Zotero.Item("book");\n' +
' item1.title = "Not in Collection";\n' +
' item1.complete();\n' +
' var item2 = new Zotero.Item("book");\n' +
' item2.id = 1;\n' +
' item2.title = "In Parent Collection";\n' +
' item2.complete();\n' +
' var item3 = new Zotero.Item("book");\n' +
' item3.id = 2;\n' +
' item3.title = "In Child Collection";\n' +
' item3.complete();\n' +
' var collection = new Zotero.Collection();\n' +
' collection.name = "Parent Collection";\n' +
' collection.children = [{"id":1}, {"type":"collection", "name":"Child Collection", "children":[{"id":2}]}];\n' +
' collection.complete();\n' +
'}' ) ) ;
let newItems = yield translate . translate ( ) ;
assert . equal ( newItems . length , 3 ) ;
2016-03-11 09:50:55 +00:00
newItems = itemsArrayToObject ( newItems ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( newItems [ "Not in Collection" ] . getCollections ( ) . length , 0 ) ;
let parentCollection = newItems [ "In Parent Collection" ] . getCollections ( ) ;
assert . equal ( parentCollection . length , 1 ) ;
parentCollection = ( yield Zotero . Collections . getAsync ( parentCollection ) ) [ 0 ] ;
assert . equal ( parentCollection . name , "Parent Collection" ) ;
assert . isTrue ( parentCollection . hasChildCollections ( ) ) ;
let childCollection = newItems [ "In Child Collection" ] . getCollections ( ) ;
assert . equal ( childCollection . length , 1 ) ;
childCollection = ( yield Zotero . Collections . getAsync ( childCollection [ 0 ] ) ) ;
assert . equal ( childCollection . name , "Child Collection" ) ;
let parentChildren = parentCollection . getChildCollections ( ) ;
assert . equal ( parentChildren . length , 1 ) ;
assert . equal ( parentChildren [ 0 ] , childCollection ) ;
} ) ;
it ( 'import translators should save attachments' , function * ( ) {
let emptyPDF = getTestPDF ( ) . path ;
let snapshot = getTestSnapshot ( ) . path ;
let myItems = [
{
"itemType" : "attachment" ,
"path" : emptyPDF ,
"title" : "Empty PDF" ,
"note" : "attachment note" ,
"tags" : TEST _TAGS
} ,
{
"itemType" : "attachment" ,
"url" : "http://www.zotero.org/" ,
"title" : "Link to zotero.org" ,
"note" : "attachment 2 note" ,
"tags" : TEST _TAGS
}
] ;
let childAttachments = myItems . slice ( ) ;
childAttachments . push ( {
"itemType" : "attachment" ,
"path" : snapshot ,
"url" : "http://www.example.com/" ,
"title" : "Snapshot" ,
"note" : "attachment 3 note" ,
"tags" : TEST _TAGS
} ) ;
myItems . push ( {
"itemType" : "book" ,
"title" : "Container Item" ,
"attachments" : childAttachments
} ) ;
2016-03-11 09:50:55 +00:00
let newItems = itemsArrayToObject ( yield saveItemsThroughTranslator ( "import" , myItems ) ) ;
2015-06-04 04:47:58 +00:00
let containedAttachments = yield Zotero . Items . getAsync ( newItems [ "Container Item" ] . getAttachments ( ) ) ;
assert . equal ( containedAttachments . length , 3 ) ;
for ( let savedAttachments of [ [ newItems [ "Empty PDF" ] , newItems [ "Link to zotero.org" ] ] ,
[ containedAttachments [ 0 ] , containedAttachments [ 1 ] ] ] ) {
assert . equal ( savedAttachments [ 0 ] . getField ( "title" ) , "Empty PDF" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( savedAttachments [ 0 ] . note , "attachment note" ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( savedAttachments [ 0 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _FILE ) ;
checkTestTags ( savedAttachments [ 0 ] ) ;
assert . equal ( savedAttachments [ 1 ] . getField ( "title" ) , "Link to zotero.org" ) ;
assert . equal ( savedAttachments [ 1 ] . getField ( "url" ) , "http://www.zotero.org/" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( savedAttachments [ 1 ] . note , "attachment 2 note" ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( savedAttachments [ 1 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _LINKED _URL ) ;
checkTestTags ( savedAttachments [ 1 ] ) ;
}
assert . equal ( containedAttachments [ 2 ] . getField ( "title" ) , "Snapshot" ) ;
assert . equal ( containedAttachments [ 2 ] . getField ( "url" ) , "http://www.example.com/" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( containedAttachments [ 2 ] . note , "attachment 3 note" ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( containedAttachments [ 2 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _URL ) ;
checkTestTags ( containedAttachments [ 2 ] ) ;
} ) ;
it ( 'import translators should save missing snapshots as links' , function * ( ) {
let missingFile = getTestDataDirectory ( ) ;
missingFile . append ( "missing" ) ;
assert . isFalse ( missingFile . exists ( ) ) ;
missingFile = missingFile . path ;
let myItems = [
{
"itemType" : "book" ,
"title" : "Container Item" ,
"attachments" : [
{
"itemType" : "attachment" ,
"path" : missingFile ,
"url" : "http://www.example.com/" ,
"title" : "Snapshot with missing file" ,
"note" : "attachment note" ,
"tags" : TEST _TAGS
}
]
}
] ;
let newItems = yield saveItemsThroughTranslator ( "import" , myItems ) ;
assert . equal ( newItems . length , 1 ) ;
assert . equal ( newItems [ 0 ] . getField ( "title" ) , "Container Item" ) ;
let containedAttachments = yield Zotero . Items . getAsync ( newItems [ 0 ] . getAttachments ( ) ) ;
assert . equal ( containedAttachments . length , 1 ) ;
assert . equal ( containedAttachments [ 0 ] . getField ( "title" ) , "Snapshot with missing file" ) ;
assert . equal ( containedAttachments [ 0 ] . getField ( "url" ) , "http://www.example.com/" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( containedAttachments [ 0 ] . note , "attachment note" ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( containedAttachments [ 0 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _LINKED _URL ) ;
checkTestTags ( containedAttachments [ 0 ] ) ;
} ) ;
it ( 'import translators should ignore missing file attachments' , function * ( ) {
let missingFile = getTestDataDirectory ( ) ;
missingFile . append ( "missing" ) ;
assert . isFalse ( missingFile . exists ( ) ) ;
missingFile = missingFile . path ;
let myItems = [
{
"itemType" : "attachment" ,
"path" : missingFile ,
"title" : "Missing file"
} ,
{
"itemType" : "book" ,
"title" : "Container Item" ,
"attachments" : [
{
"itemType" : "attachment" ,
"path" : missingFile ,
"title" : "Missing file"
}
]
}
] ;
let newItems = yield saveItemsThroughTranslator ( "import" , myItems ) ;
assert . equal ( newItems . length , 1 ) ;
assert . equal ( newItems [ 0 ] . getField ( "title" ) , "Container Item" ) ;
assert . equal ( newItems [ 0 ] . getAttachments ( ) . length , 0 ) ;
} ) ;
2019-01-08 07:07:15 +00:00
2019-01-26 05:11:27 +00:00
it ( 'import translators should save link attachments' , async function ( ) {
// Start a local server so we can make sure a web request isn't made for the URL
var port = 16213 ;
var baseURL = ` http://127.0.0.1: ${ port } / ` ;
var httpd = new HttpServer ( ) ;
httpd . start ( port ) ;
var callCount = 0 ;
var handler = function ( _request , response ) {
callCount ++ ;
response . setStatusLine ( null , 200 , "OK" ) ;
response . write ( "<html><head><title>Title</title><body>Body</body></html>" ) ;
} ;
httpd . registerPathHandler ( "/1" , { handle : handler } ) ;
httpd . registerPathHandler ( "/2" , { handle : handler } ) ;
var items = [ {
itemType : "book" ,
title : "Item" ,
attachments : [
// With mimeType
{
itemType : "attachment" ,
linkMode : Zotero . Attachments . LINK _MODE _LINKED _URL ,
title : "Link 1" ,
url : baseURL + "1" ,
mimeType : 'text/html'
} ,
// Without mimeType
{
itemType : "attachment" ,
linkMode : Zotero . Attachments . LINK _MODE _LINKED _URL ,
title : "Link 2" ,
url : baseURL + "2"
}
]
} ] ;
var newItems = itemsArrayToObject ( await saveItemsThroughTranslator ( "import" , items ) ) ;
assert . equal ( callCount , 0 ) ;
var attachments = await Zotero . Items . getAsync ( newItems . Item . getAttachments ( ) ) ;
assert . equal ( attachments . length , 2 ) ;
assert . equal ( attachments [ 0 ] . getField ( "title" ) , "Link 1" ) ;
assert . equal ( attachments [ 0 ] . getField ( "url" ) , baseURL + "1" ) ;
assert . equal ( attachments [ 0 ] . attachmentContentType , "text/html" ) ;
assert . equal ( attachments [ 0 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _LINKED _URL ) ;
assert . equal ( attachments [ 1 ] . getField ( "title" ) , "Link 2" ) ;
assert . equal ( attachments [ 1 ] . getField ( "url" ) , baseURL + "2" ) ;
assert . equal ( attachments [ 1 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _LINKED _URL ) ;
assert . equal ( attachments [ 1 ] . attachmentContentType , '' ) ;
await new Promise ( function ( resolve ) {
httpd . stop ( resolve ) ;
} ) ;
} ) ;
2019-01-08 07:07:15 +00:00
it ( "import translators should save linked-URL attachments with savingAttachments: false" , async function ( ) {
var json = [
{
itemType : "journalArticle" ,
title : "Parent Item" ,
attachments : [
// snapshot: false
{
title : "Link" ,
mimeType : "text/html" ,
url : "http://example.com" ,
snapshot : false
} ,
// linkMode (used by RDF import)
{
title : "Link" ,
mimeType : "text/html" ,
url : "http://example.com" ,
linkMode : Zotero . Attachments . LINK _MODE _LINKED _URL
}
]
}
] ;
var newItems = itemsArrayToObject (
await saveItemsThroughTranslator (
"import" ,
json ,
{
saveAttachments : false
}
)
) ;
var attachmentIDs = newItems [ "Parent Item" ] . getAttachments ( ) ;
assert . lengthOf ( attachmentIDs , 2 ) ;
var attachments = await Zotero . Items . getAsync ( attachmentIDs ) ;
assert . equal ( attachments [ 0 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _LINKED _URL ) ;
assert . equal ( attachments [ 1 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _LINKED _URL ) ;
} ) ;
2019-03-02 10:56:32 +00:00
it ( "import translators should save linked-file attachments with linkFiles: true" , async function ( ) {
var testDir = getTestDataDirectory ( ) . path ;
var file1 = OS . Path . join ( testDir , 'test.pdf' ) ;
var file2 = OS . Path . join ( testDir , 'test.html' ) ;
var file2URL = "http://example.com" ;
var json = [
{
itemType : "journalArticle" ,
title : "Parent Item" ,
attachments : [
{
title : "PDF" ,
mimeType : "application/pdf" ,
path : file1
} ,
{
title : "Snapshot" ,
mimeType : "text/html" ,
charset : "utf-8" ,
url : file2URL ,
path : file2
}
]
}
] ;
var newItems = itemsArrayToObject (
await saveItemsThroughTranslator (
"import" ,
json ,
{
linkFiles : true
}
)
) ;
var attachmentIDs = newItems [ "Parent Item" ] . getAttachments ( ) ;
assert . lengthOf ( attachmentIDs , 2 ) ;
var attachments = await Zotero . Items . getAsync ( attachmentIDs ) ;
assert . equal ( attachments [ 0 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _LINKED _FILE ) ;
assert . equal ( attachments [ 0 ] . attachmentContentType , 'application/pdf' ) ;
assert . equal ( attachments [ 1 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _LINKED _FILE ) ;
assert . equal ( attachments [ 1 ] . attachmentContentType , 'text/html' ) ;
assert . equal ( attachments [ 1 ] . attachmentCharset , 'utf-8' ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( attachments [ 1 ] . note , file2URL ) ;
2019-03-02 10:56:32 +00:00
} ) ;
it ( "import translators shouldn't save linked-file attachment with linkFiles: true if path is within current storage directory" , async function ( ) {
var attachment = await importFileAttachment ( 'test.png' ) ;
var path = attachment . getFilePath ( ) ;
var json = [
{
itemType : "journalArticle" ,
title : "Parent Item" ,
attachments : [
{
title : "PDF" ,
mimeType : "application/pdf" ,
path
}
]
}
] ;
var newItems = itemsArrayToObject (
await saveItemsThroughTranslator (
"import" ,
json ,
{
linkFiles : true
}
)
) ;
var attachmentIDs = newItems [ "Parent Item" ] . getAttachments ( ) ;
assert . lengthOf ( attachmentIDs , 1 ) ;
var attachments = await Zotero . Items . getAsync ( attachmentIDs ) ;
assert . equal ( attachments [ 0 ] . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _FILE ) ;
var newPath = attachments [ 0 ] . getFilePath ( ) ;
assert . ok ( newPath ) ;
assert . notEqual ( newPath , path ) ;
} ) ;
2015-06-07 22:38:00 +00:00
it ( 'web translators should set accessDate to current date' , function * ( ) {
let myItem = {
"itemType" : "webpage" ,
"title" : "Test Item" ,
"url" : "http://www.zotero.org/"
} ;
let newItems = yield saveItemsThroughTranslator ( "web" , [ myItem ] ) ;
2017-08-19 13:21:57 +00:00
let currentDate = new Date ( ) ;
let delta = currentDate - Zotero . Date . sqlToDate ( newItems [ 0 ] . getField ( "accessDate" ) , true ) ;
assert . isAbove ( delta , - 500 ) ;
assert . isBelow ( delta , 5000 ) ;
} ) ;
it ( 'web translators should set accessDate to current date for CURRENT_TIMESTAMP' , function * ( ) {
let myItem = {
itemType : "webpage" ,
title : "Test Item" ,
url : "https://www.zotero.org/" ,
accessDate : 'CURRENT_TIMESTAMP'
} ;
let newItems = yield saveItemsThroughTranslator ( "web" , [ myItem ] ) ;
2015-06-07 22:38:00 +00:00
let currentDate = new Date ( ) ;
let delta = currentDate - Zotero . Date . sqlToDate ( newItems [ 0 ] . getField ( "accessDate" ) , true ) ;
assert . isAbove ( delta , - 500 ) ;
assert . isBelow ( delta , 5000 ) ;
} ) ;
2015-06-04 04:47:58 +00:00
it ( 'web translators should save attachments' , function * ( ) {
let myItems = [
{
"itemType" : "book" ,
"title" : "Container Item" ,
"attachments" : [
{
"url" : "http://www.zotero.org/" ,
"title" : "Link to zotero.org" ,
"note" : "attachment note" ,
"tags" : TEST _TAGS ,
"snapshot" : false
} ,
{
"url" : "http://127.0.0.1:23119/test/translate/test.html" ,
"title" : "Test Snapshot" ,
"note" : "attachment 2 note" ,
"tags" : TEST _TAGS
} ,
{
"url" : "http://127.0.0.1:23119/test/translate/test.pdf" ,
"title" : "Test PDF" ,
"note" : "attachment 3 note" ,
"tags" : TEST _TAGS
}
]
}
] ;
let newItems = yield saveItemsThroughTranslator ( "web" , myItems ) ;
assert . equal ( newItems . length , 1 ) ;
2016-03-11 09:50:55 +00:00
let containedAttachments = itemsArrayToObject ( yield Zotero . Items . getAsync ( newItems [ 0 ] . getAttachments ( ) ) ) ;
2015-06-04 04:47:58 +00:00
let link = containedAttachments [ "Link to zotero.org" ] ;
assert . equal ( link . getField ( "url" ) , "http://www.zotero.org/" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( link . note , "attachment note" ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( link . attachmentLinkMode , Zotero . Attachments . LINK _MODE _LINKED _URL ) ;
checkTestTags ( link , true ) ;
let snapshot = containedAttachments [ "Test Snapshot" ] ;
assert . equal ( snapshot . getField ( "url" ) , "http://127.0.0.1:23119/test/translate/test.html" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( snapshot . note , "attachment 2 note" ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( snapshot . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _URL ) ;
assert . equal ( snapshot . attachmentContentType , "text/html" ) ;
checkTestTags ( snapshot , true ) ;
let pdf = containedAttachments [ "Test PDF" ] ;
assert . equal ( pdf . getField ( "url" ) , "http://127.0.0.1:23119/test/translate/test.pdf" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( pdf . note , "attachment 3 note" ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( pdf . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _URL ) ;
assert . equal ( pdf . attachmentContentType , "application/pdf" ) ;
checkTestTags ( pdf , true ) ;
} ) ;
2017-08-19 10:57:54 +00:00
it ( 'web translators should save attachment from browser document' , function * ( ) {
2023-04-14 15:37:07 +00:00
let browser = yield HiddenBrowser . create ( "http://127.0.0.1:23119/test/translate/test.html" ) ;
let doc = yield HiddenBrowser . getDocument ( browser ) ;
2015-06-04 04:47:58 +00:00
let translate = new Zotero . Translate . Web ( ) ;
translate . setDocument ( doc ) ;
translate . setTranslator ( buildDummyTranslator ( 4 ,
'function detectWeb() {}\n' +
'function doWeb(doc) {\n' +
' var item = new Zotero.Item("book");\n' +
' item.title = "Container Item";\n' +
' item.attachments = [{\n' +
' "document":doc,\n' +
' "title":"Snapshot from Document",\n' +
' "note":"attachment note",\n' +
' "tags":' + JSON . stringify ( TEST _TAGS ) + '\n' +
' }];\n' +
' item.complete();\n' +
'}' ) ) ;
let newItems = yield translate . translate ( ) ;
assert . equal ( newItems . length , 1 ) ;
2017-08-19 10:57:54 +00:00
let containedAttachments = Zotero . Items . get ( newItems [ 0 ] . getAttachments ( ) ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( containedAttachments . length , 1 ) ;
let snapshot = containedAttachments [ 0 ] ;
assert . equal ( snapshot . getField ( "url" ) , "http://127.0.0.1:23119/test/translate/test.html" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( snapshot . note , "attachment note" ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( snapshot . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _URL ) ;
assert . equal ( snapshot . attachmentContentType , "text/html" ) ;
checkTestTags ( snapshot , true ) ;
2023-04-14 15:37:07 +00:00
HiddenBrowser . destroy ( browser ) ;
2015-06-04 04:47:58 +00:00
} ) ;
2017-08-19 10:57:54 +00:00
it ( 'web translators should save attachment from non-browser document' , function * ( ) {
return Zotero . HTTP . processDocuments (
"http://127.0.0.1:23119/test/translate/test.html" ,
async function ( doc ) {
let translate = new Zotero . Translate . Web ( ) ;
translate . setDocument ( doc ) ;
translate . setTranslator ( buildDummyTranslator ( 4 ,
'function detectWeb() {}\n' +
'function doWeb(doc) {\n' +
' var item = new Zotero.Item("book");\n' +
' item.title = "Container Item";\n' +
' item.attachments = [{\n' +
' "document":doc,\n' +
' "title":"Snapshot from Document",\n' +
' "note":"attachment note",\n' +
' "tags":' + JSON . stringify ( TEST _TAGS ) + '\n' +
' }];\n' +
' item.complete();\n' +
'}' ) ) ;
let newItems = await translate . translate ( ) ;
assert . equal ( newItems . length , 1 ) ;
let containedAttachments = Zotero . Items . get ( newItems [ 0 ] . getAttachments ( ) ) ;
assert . equal ( containedAttachments . length , 1 ) ;
let snapshot = containedAttachments [ 0 ] ;
assert . equal ( snapshot . getField ( "url" ) , "http://127.0.0.1:23119/test/translate/test.html" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( snapshot . note , "attachment note" ) ;
2017-08-19 10:57:54 +00:00
assert . equal ( snapshot . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _URL ) ;
assert . equal ( snapshot . attachmentContentType , "text/html" ) ;
checkTestTags ( snapshot , true ) ;
}
) ;
} ) ;
2015-06-04 04:47:58 +00:00
it ( 'web translators should ignore attachments that return error codes' , function * ( ) {
this . timeout ( 60000 ) ;
let myItems = [
{
"itemType" : "book" ,
"title" : "Container Item" ,
"attachments" : [
{
"url" : "http://127.0.0.1:23119/test/translate/does_not_exist.html" ,
"title" : "Non-Existent HTML"
} ,
{
"url" : "http://127.0.0.1:23119/test/translate/does_not_exist.pdf" ,
"title" : "Non-Existent PDF"
}
]
}
] ;
let newItems = yield saveItemsThroughTranslator ( "web" , myItems ) ;
assert . equal ( newItems . length , 1 ) ;
let containedAttachments = yield Zotero . Items . getAsync ( newItems [ 0 ] . getAttachments ( ) ) ;
assert . equal ( containedAttachments . length , 0 ) ;
} ) ;
it ( 'web translators should save PDFs only if the content type matches' , function * ( ) {
this . timeout ( 60000 ) ;
let myItems = [
{
"itemType" : "book" ,
"title" : "Container Item" ,
"attachments" : [
{
"url" : "http://127.0.0.1:23119/test/translate/test.html" ,
"mimeType" : "application/pdf" ,
"title" : "Test PDF with wrong mime type"
} ,
{
"url" : "http://127.0.0.1:23119/test/translate/test.pdf" ,
"mimeType" : "application/pdf" ,
"title" : "Test PDF" ,
"note" : "attachment note" ,
"tags" : TEST _TAGS
}
]
}
] ;
let newItems = yield saveItemsThroughTranslator ( "web" , myItems ) ;
assert . equal ( newItems . length , 1 ) ;
let containedAttachments = yield Zotero . Items . getAsync ( newItems [ 0 ] . getAttachments ( ) ) ;
assert . equal ( containedAttachments . length , 1 ) ;
let pdf = containedAttachments [ 0 ] ;
assert . equal ( pdf . getField ( "title" ) , "Test PDF" ) ;
assert . equal ( pdf . getField ( "url" ) , "http://127.0.0.1:23119/test/translate/test.pdf" ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( pdf . note , "attachment note" ) ;
2015-06-04 04:47:58 +00:00
assert . equal ( pdf . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _URL ) ;
checkTestTags ( pdf , true ) ;
} ) ;
2016-09-20 13:10:26 +00:00
it ( 'should not convert tags to canonical form in child translators' , function * ( ) {
var childTranslator = buildDummyTranslator ( 1 ,
` function detectWeb() {}
function doImport ( ) {
var item = new Zotero . Item ;
item . itemType = "book" ;
item . title = "The Definitive Guide of Owls" ;
item . tags = [ 'owl' , 'tag' ] ;
item . complete ( ) ;
2016-09-27 14:43:56 +00:00
} ` , {translatorID: 'child-dummy-translator'}
2016-09-20 13:10:26 +00:00
) ;
sinon . stub ( Zotero . Translators , 'get' ) . withArgs ( 'child-dummy-translator' ) . returns ( childTranslator ) ;
var parentTranslator = buildDummyTranslator ( 1 ,
` function detectWeb() {}
function doImport ( ) {
var translator = Zotero . loadTranslator ( "import" ) ;
translator . setTranslator ( 'child-dummy-translator' ) ;
translator . setHandler ( 'itemDone' , Zotero . childItemDone ) ;
translator . translate ( ) ;
} `
) ;
function childItemDone ( obj , item ) {
// Non-canonical tags after child translator is done
assert . deepEqual ( [ 'owl' , 'tag' ] , item . tags ) ;
item . complete ( ) ;
}
var translate = new Zotero . Translate . Import ( ) ;
translate . setTranslator ( parentTranslator ) ;
translate . setString ( "" ) ;
yield translate . _loadTranslator ( parentTranslator ) ;
translate . _sandboxManager . importObject ( { childItemDone } ) ;
var items = yield translate . translate ( ) ;
// Canonicalized tags after parent translator
assert . deepEqual ( [ { tag : 'owl' } , { tag : 'tag' } ] , items [ 0 ] . getTags ( ) ) ;
Zotero . Translators . get . restore ( ) ;
} ) ;
2015-06-04 04:47:58 +00:00
} ) ;
2016-12-09 09:36:42 +00:00
2017-01-28 01:51:12 +00:00
2017-08-19 10:57:54 +00:00
describe ( "#processDocuments()" , function ( ) {
var url = "http://127.0.0.1:23119/test/translate/test.html" ;
var doc ;
beforeEach ( function * ( ) {
// This is the main processDocuments, not the translation sandbox one being tested
doc = ( yield Zotero . HTTP . processDocuments ( url , doc => doc ) ) [ 0 ] ;
} ) ;
it ( "should provide document object" , async function ( ) {
var translate = new Zotero . Translate . Web ( ) ;
translate . setDocument ( doc ) ;
translate . setTranslator (
buildDummyTranslator (
4 ,
` function detectWeb() {}
function doWeb ( doc ) {
ZU . processDocuments (
doc . location . href + '?t' ,
function ( doc ) {
var item = new Zotero . Item ( "book" ) ;
item . title = "Container Item" ;
// document.location
item . url = doc . location . href ;
// document.evaluate()
item . extra = doc
. evaluate ( '//p' , doc , null , XPathResult . ANY _TYPE , null )
. iterateNext ( )
. textContent ;
item . attachments = [ {
document : doc ,
title : "Snapshot from Document" ,
note : "attachment note" ,
tags : $ { JSON . stringify ( TEST _TAGS ) }
} ] ;
item . complete ( ) ;
}
) ;
} `
)
) ;
var newItems = await translate . translate ( ) ;
assert . equal ( newItems . length , 1 ) ;
var item = newItems [ 0 ] ;
assert . equal ( item . getField ( 'url' ) , url + '?t' ) ;
assert . include ( item . getField ( 'extra' ) , 'your research sources' ) ;
var containedAttachments = Zotero . Items . get ( newItems [ 0 ] . getAttachments ( ) ) ;
assert . equal ( containedAttachments . length , 1 ) ;
var snapshot = containedAttachments [ 0 ] ;
assert . equal ( snapshot . getField ( "url" ) , url + '?t' ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( snapshot . note , "attachment note" ) ;
2017-08-19 10:57:54 +00:00
assert . equal ( snapshot . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _URL ) ;
assert . equal ( snapshot . attachmentContentType , "text/html" ) ;
checkTestTags ( snapshot , true ) ;
} ) ;
it ( "should use loaded document instead of reloading if possible" , function * ( ) {
var translate = new Zotero . Translate . Web ( ) ;
translate . setDocument ( doc ) ;
translate . setTranslator (
buildDummyTranslator (
4 ,
` function detectWeb() {}
function doWeb ( doc ) {
ZU . processDocuments (
doc . location . href ,
function ( doc ) {
var item = new Zotero . Item ( "book" ) ;
item . title = "Container Item" ;
// document.location
item . url = doc . location . href ;
// document.evaluate()
item . extra = doc
. evaluate ( '//p' , doc , null , XPathResult . ANY _TYPE , null )
. iterateNext ( )
. textContent ;
item . attachments = [ {
document : doc ,
title : "Snapshot from Document" ,
note : "attachment note" ,
tags : $ { JSON . stringify ( TEST _TAGS ) }
} ] ;
item . complete ( ) ;
}
) ;
} `
)
) ;
var newItems = yield translate . translate ( ) ;
assert . equal ( newItems . length , 1 ) ;
var item = newItems [ 0 ] ;
assert . equal ( item . getField ( 'url' ) , url ) ;
assert . include ( item . getField ( 'extra' ) , 'your research sources' ) ;
var containedAttachments = Zotero . Items . get ( newItems [ 0 ] . getAttachments ( ) ) ;
assert . equal ( containedAttachments . length , 1 ) ;
var snapshot = containedAttachments [ 0 ] ;
assert . equal ( snapshot . getField ( "url" ) , url ) ;
2020-08-25 18:22:23 +00:00
assert . equal ( snapshot . note , "attachment note" ) ;
2017-08-19 10:57:54 +00:00
assert . equal ( snapshot . attachmentLinkMode , Zotero . Attachments . LINK _MODE _IMPORTED _URL ) ;
assert . equal ( snapshot . attachmentContentType , "text/html" ) ;
checkTestTags ( snapshot , true ) ;
} ) ;
} ) ;
2019-07-10 08:48:32 +00:00
describe ( "#setTranslatorProvider()" , function ( ) {
var url = "http://127.0.0.1:23119/test/translate/test.html" ;
var doc ;
beforeEach ( function * ( ) {
// This is the main processDocuments, not the translation sandbox one being tested
doc = ( yield Zotero . HTTP . processDocuments ( url , doc => doc ) ) [ 0 ] ;
} ) ;
it ( "should set a custom version of Zotero.Translators" , async function ( ) {
// Create a dummy translator to be returned by the stub methods
var info = {
translatorID : "e6111720-1f6c-42b0-a487-99b9fa50b8a1" ,
label : "Test" ,
creator : "Creator" ,
target : "^http:\/\/127.0.0.1:23119\/test" ,
minVersion : "5.0" ,
maxVersion : "" ,
priority : 100 ,
translatorType : 4 ,
browserSupport : "gcsibv" ,
lastUpdated : "2019-07-10 05:50:39" ,
cacheCode : true
} ;
info . code = JSON . stringify ( info , null , '\t' ) + "\n\n"
+ "function detectWeb(doc, url) {"
+ "return 'journalArticle';"
+ "}\n"
+ "function doWeb(doc, url) {"
+ "var item = new Zotero.Item('journalArticle');"
+ "item.title = 'Test';"
+ "item.complete();"
+ "}\n" ;
var translator = new Zotero . Translator ( info ) ;
var translate = new Zotero . Translate . Web ( ) ;
var provider = Zotero . Translators . makeTranslatorProvider ( {
get : function ( translatorID ) {
if ( translatorID == info . translatorID ) {
return translator ;
}
return false ;
} ,
getAllForType : async function ( type ) {
var translators = [ ] ;
if ( type == 'web' ) {
translators . push ( translator ) ;
}
return translators ;
}
} ) ;
translate . setTranslatorProvider ( provider ) ;
translate . setDocument ( doc ) ;
var translators = await translate . getTranslators ( ) ;
translate . setTranslator ( translators [ 0 ] ) ;
var newItems = await translate . translate ( ) ;
assert . equal ( newItems . length , 1 ) ;
var item = newItems [ 0 ] ;
assert . equal ( item . getField ( 'title' ) , 'Test' ) ;
} ) ;
it ( "should set a custom version of Zotero.Translators in a child translator" , async function ( ) {
// Create dummy translators to be returned by the stub methods
var info1 = {
translatorID : "e6111720-1f6c-42b0-a487-99b9fa50b8a1" ,
label : "Test" ,
creator : "Creator" ,
target : "^http:\/\/127.0.0.1:23119\/test" ,
minVersion : "5.0" ,
maxVersion : "" ,
priority : 100 ,
translatorType : 4 ,
browserSupport : "gcsibv" ,
lastUpdated : "2019-07-10 05:50:39" ,
cacheCode : true
} ;
info1 . code = JSON . stringify ( info1 , null , '\t' ) + "\n\n"
+ "function detectWeb(doc, url) {"
+ "return 'journalArticle';"
+ "}\n"
+ "function doWeb(doc, url) {"
+ "var translator = Zotero.loadTranslator('import');"
+ "translator.setTranslator('86e58f50-4e2d-4ee8-8a20-bafa225381fa');"
+ "translator.setString('foo\\n');"
+ "translator.setHandler('itemDone', function(obj, item) {"
+ "item.complete();"
+ "});"
+ "translator.translate();"
+ "}\n" ;
var translator1 = new Zotero . Translator ( info1 ) ;
var info2 = {
translatorID : "86e58f50-4e2d-4ee8-8a20-bafa225381fa" ,
label : "Child Test" ,
creator : "Creator" ,
target : "" ,
minVersion : "5.0" ,
maxVersion : "" ,
priority : 100 ,
translatorType : 3 ,
browserSupport : "gcsibv" ,
lastUpdated : "2019-07-19 06:22:21" ,
cacheCode : true
} ;
info2 . code = JSON . stringify ( info2 , null , '\t' ) + "\n\n"
+ "function detectImport() {"
+ "return true;"
+ "}\n"
+ "function doImport() {"
+ "var item = new Zotero.Item('journalArticle');"
+ "item.title = 'Test';"
+ "item.complete();"
+ "}\n" ;
var translator2 = new Zotero . Translator ( info2 ) ;
var translate = new Zotero . Translate . Web ( ) ;
var provider = Zotero . Translators . makeTranslatorProvider ( {
get : function ( translatorID ) {
switch ( translatorID ) {
case info1 . translatorID :
return translator1 ;
case info2 . translatorID :
return translator2 ;
}
return false ;
} ,
getAllForType : async function ( type ) {
var translators = [ ] ;
if ( type == 'web' ) {
translators . push ( translator1 ) ;
}
if ( type == 'import' ) {
translators . push ( translator2 ) ;
}
return translators ;
}
} ) ;
translate . setTranslatorProvider ( provider ) ;
translate . setDocument ( doc ) ;
var translators = await translate . getTranslators ( ) ;
translate . setTranslator ( translators [ 0 ] ) ;
var newItems = await translate . translate ( ) ;
assert . equal ( newItems . length , 1 ) ;
var item = newItems [ 0 ] ;
assert . equal ( item . getField ( 'title' ) , 'Test' ) ;
} ) ;
} ) ;
2017-01-28 01:51:12 +00:00
describe ( "Translators" , function ( ) {
it ( "should round-trip child attachment via BibTeX" , function * ( ) {
var item = yield createDataObject ( 'item' ) ;
yield importFileAttachment ( 'test.png' , { parentItemID : item . id } ) ;
var translation = new Zotero . Translate . Export ( ) ;
var tmpDir = yield getTempDirectory ( ) ;
var exportDir = OS . Path . join ( tmpDir , 'export' ) ;
translation . setLocation ( Zotero . File . pathToFile ( exportDir ) ) ;
translation . setItems ( [ item ] ) ;
translation . setTranslator ( "9cb70025-a888-4a29-a210-93ec52da40d4" ) ;
translation . setDisplayOptions ( {
exportFileData : true
} ) ;
yield translation . translate ( ) ;
var exportFile = OS . Path . join ( exportDir , 'export.bib' ) ;
assert . isTrue ( yield OS . File . exists ( exportFile ) ) ;
var translation = new Zotero . Translate . Import ( ) ;
translation . setLocation ( Zotero . File . pathToFile ( exportFile ) ) ;
var translators = yield translation . getTranslators ( ) ;
translation . setTranslator ( translators [ 0 ] ) ;
var importCollection = yield createDataObject ( 'collection' ) ;
var items = yield translation . translate ( {
libraryID : Zotero . Libraries . userLibraryID ,
collections : [ importCollection . id ]
} ) ;
assert . lengthOf ( items , 1 ) ;
var attachments = items [ 0 ] . getAttachments ( ) ;
assert . lengthOf ( attachments , 1 ) ;
var attachment = Zotero . Items . get ( attachments [ 0 ] ) ;
assert . isTrue ( yield attachment . fileExists ( ) ) ;
} ) ;
2021-01-25 08:15:26 +00:00
it ( "should round-trip collections via Zotero RDF" , async function ( ) {
this . timeout ( 60000 ) ;
await resetDB ( ) ;
var c1 = await createDataObject ( 'collection' , { name : '1' } ) ;
var c2 = await createDataObject ( 'collection' , { name : '2' , parentID : c1 . id } ) ;
var c3 = await createDataObject ( 'collection' , { name : '3' , parentID : c2 . id } ) ;
var c4 = await createDataObject ( 'collection' , { name : '4' , parentID : c3 . id } ) ;
var c5 = await createDataObject ( 'collection' , { name : '5' , parentID : c4 . id } ) ;
2021-11-25 05:21:32 +00:00
// Add item, standalone note, and standalone attachment to collection
var item = await createDataObject (
'item' ,
{ collections : [ c5 . id ] , title : Zotero . Utilities . randomString ( ) }
) ;
var note = await createDataObject (
'item' ,
{ itemType : 'note' , collections : [ c5 . id ] , note : Zotero . Utilities . randomString ( ) }
) ;
var attachment = await importFileAttachment ( 'test.pdf' , {
url : 'https://example.com/test.pdf' ,
title : Zotero . Utilities . randomString ( ) ,
collections : [ c5 . id ]
} ) ;
2021-01-25 08:15:26 +00:00
var tmpDir = await getTempDirectory ( ) ;
2021-11-25 05:21:32 +00:00
var libraryExportDir = OS . Path . join ( tmpDir , 'export-library' ) ;
var libraryExportFile = OS . Path . join ( libraryExportDir , 'export-library.rdf' ) ;
var collectionExportDir = OS . Path . join ( tmpDir , 'export-collection' ) ;
var collectionExportFile = OS . Path . join ( collectionExportDir , 'export-collection.rdf' ) ;
2021-01-25 08:15:26 +00:00
// Export library
var translation = new Zotero . Translate . Export ( ) ;
2021-11-25 05:21:32 +00:00
translation . setLocation ( Zotero . File . pathToFile ( libraryExportDir ) ) ;
2021-01-25 08:15:26 +00:00
translation . setLibraryID ( Zotero . Libraries . userLibraryID ) ;
2021-11-25 05:21:32 +00:00
translation . setDisplayOptions ( {
exportFileData : true ,
exportNotes : true
} ) ;
2021-01-25 08:15:26 +00:00
translation . setTranslator ( '14763d24-8ba0-45df-8f52-b8d1108e7ac9' ) ; // Zotero RDF
await translation . translate ( ) ;
// Export top-most collection
translation = new Zotero . Translate . Export ( ) ;
2021-11-25 05:21:32 +00:00
translation . setLocation ( Zotero . File . pathToFile ( collectionExportDir ) ) ;
2021-01-25 08:15:26 +00:00
translation . setCollection ( c1 ) ;
2021-11-25 05:21:32 +00:00
translation . setDisplayOptions ( {
exportFileData : true ,
exportNotes : true
} ) ;
2021-01-25 08:15:26 +00:00
translation . setTranslator ( '14763d24-8ba0-45df-8f52-b8d1108e7ac9' ) ; // Zotero RDF
await translation . translate ( ) ;
async function check ( file , mode ) {
var collectionNames = [ c1 . name , c2 . name , c3 . name , c4 . name , c5 . name ] ;
var translation = new Zotero . Translate . Import ( ) ;
translation . setLocation ( Zotero . File . pathToFile ( file ) ) ;
var translators = await translation . getTranslators ( ) ;
translation . setTranslator ( translators [ 0 ] ) ;
var importCollection = await createDataObject ( 'collection' ) ;
await translation . translate ( {
libraryID : Zotero . Libraries . userLibraryID ,
collections : [ importCollection . id ]
} ) ;
// When exporting a library, the top-most collection should be included. When
// exporting a collection, the selected collection isn't included, so remove it.
if ( mode == 'collection' ) {
collectionNames . shift ( ) ;
}
var collections = importCollection . getChildCollections ( ) ;
assert . lengthOf ( collections , 1 , mode ) ;
assert . equal ( collections [ 0 ] . name , collectionNames . shift ( ) , mode )
var name ;
while ( name = collectionNames . shift ( ) ) {
collections = collections [ 0 ] . getChildCollections ( ) ;
assert . lengthOf ( collections , 1 , mode ) ;
2021-11-25 05:21:32 +00:00
let c = collections [ 0 ] ;
assert . equal ( c . name , name , mode ) ;
// Get the collection we imported items into
if ( name == c5 . name ) {
// Make sure items were imported and added to collection
let titles = c . getChildItems ( ) . map ( x => x . getDisplayTitle ( ) ) ;
assert . sameMembers ( titles , [ item , note , attachment ] . map ( x => x . getDisplayTitle ( ) ) ) ;
}
// Other collections should be empty
else {
assert . lengthOf ( c . getChildItems ( ) , 0 ) ;
}
2021-01-25 08:15:26 +00:00
}
}
await check ( libraryExportFile , 'library' ) ;
await check ( collectionExportFile , 'collection' ) ;
} ) ;
2017-01-28 01:51:12 +00:00
} ) ;
2021-11-06 03:12:37 +00:00
describe ( "Async translators" , function ( ) {
var htmlURL = "http://127.0.0.1:23119/test/translate/test.html" ;
var jsonURL = "http://127.0.0.1:23119/test/translate/test.json" ;
var notFoundURL = "http://127.0.0.1:23119/test/translate/does_not_exist.html"
var doc ;
before ( function * ( ) {
setupAttachmentEndpoints ( ) ;
setupAsyncEndpoints ( ) ;
doc = ( yield Zotero . HTTP . processDocuments ( htmlURL , doc => doc ) ) [ 0 ] ;
} ) ;
it ( 'should support async detectWeb' , async function ( ) {
var info = {
translatorID : "e6111720-1f6c-42b0-a487-99b9fa50b8a1" ,
label : "Test" ,
creator : "Creator" ,
target : "^http:\/\/127.0.0.1:23119\/test" ,
minVersion : "5.0" ,
maxVersion : "" ,
priority : 100 ,
translatorType : 4 ,
browserSupport : "gcsibv" ,
lastUpdated : "2021-10-23 00:00:00" ,
cacheCode : true
} ;
info . code = JSON . stringify ( info , null , '\t' ) + "\n\n"
+ `
// asynchronous detectWeb
async function detectWeb ( ) {
await doNothing ( ) ;
return 'book' ;
}
function doNothing ( ) {
return new Promise ( resolve => resolve ( 'nothing' ) ) ;
}
// synchronous doWeb
function doWeb ( doc ) {
let item = new Zotero . Item ( 'webpage' ) ;
item . title = 'Untitled' ;
item . complete ( ) ;
}
` ;
var translator = new Zotero . Translator ( info ) ;
var translate = new Zotero . Translate . Web ( ) ;
var provider = Zotero . Translators . makeTranslatorProvider ( {
get : function ( translatorID ) {
if ( translatorID == info . translatorID ) {
return translator ;
}
return false ;
} ,
getAllForType : async function ( type ) {
var translators = [ ] ;
if ( type == 'web' ) {
translators . push ( translator ) ;
}
return translators ;
}
} ) ;
translate . setTranslatorProvider ( provider ) ;
translate . setDocument ( doc ) ;
var translators = await translate . getTranslators ( ) ;
assert . equal ( translators . length , 1 ) ;
assert . equal ( translators [ 0 ] . translatorID , info . translatorID ) ;
var newItems = await translate . translate ( ) ;
assert . equal ( newItems . length , 1 ) ;
assert . equal ( newItems [ 0 ] . getField ( 'title' ) , 'Untitled' ) ;
} ) ;
it ( 'should support async doWeb' , async function ( ) {
var translate = new Zotero . Translate . Web ( ) ;
translate . setDocument ( doc ) ;
translate . setTranslator (
buildDummyTranslator (
4 ,
`
function detectWeb ( ) { }
async function doWeb ( doc ) {
let item = new Zotero . Item ( 'webpage' ) ;
let otherDoc = await requestDocument ( '${htmlURL}' ) ;
item . title = otherDoc . title ;
let { status } = await request ( '${htmlURL}' ) ;
item . abstractNote = 'Status ' + status ;
item . complete ( ) ;
let json = await requestJSON ( '${jsonURL}' ) ;
if ( json . success ) {
item = new Zotero . Item ( 'webpage' ) ;
item . title = 'JSON Test' ;
item . complete ( ) ;
}
}
`
)
) ;
var newItems = await translate . translate ( ) ;
assert . equal ( newItems . length , 2 ) ;
var item = newItems [ 0 ] ;
assert . equal ( item . getField ( 'title' ) , 'Test' ) ;
assert . equal ( item . getField ( 'abstractNote' ) , 'Status 200' ) ;
var item = newItems [ 1 ] ;
assert . equal ( item . getField ( 'title' ) , 'JSON Test' ) ;
} ) ;
it ( 'should not fail translation on a non-200 status code' , async function ( ) {
var translate = new Zotero . Translate . Web ( ) ;
translate . setDocument ( doc ) ;
translate . setTranslator (
buildDummyTranslator (
4 ,
` function detectWeb() {}
async function doWeb ( doc ) {
await request ( '${notFoundURL}' ) . catch ( e => { } ) ;
let item = new Zotero . Item ( 'webpage' ) ;
item . title = 'Nothing' ;
item . complete ( ) ;
} `
)
) ;
var newItems = await translate . translate ( ) ;
assert . equal ( newItems . length , 1 ) ;
var item = newItems [ 0 ] ;
assert . equal ( item . getField ( 'title' ) , 'Nothing' ) ;
} ) ;
} ) ;
2017-01-28 01:51:12 +00:00
2016-12-09 09:36:42 +00:00
describe ( "ItemSaver" , function ( ) {
describe ( "#saveCollections()" , function ( ) {
it ( "should add top-level collections to specified collection" , function * ( ) {
var collection = yield createDataObject ( 'collection' ) ;
var collections = [
{
name : "Collection" ,
type : "collection" ,
children : [ ]
}
] ;
var items = [
{
itemType : "book" ,
title : "Test"
}
] ;
var translation = new Zotero . Translate . Import ( ) ;
translation . setString ( "" ) ;
translation . setTranslator ( buildDummyTranslator (
"import" ,
"function detectImport() {}\n"
+ "function doImport() {\n"
+ " var json = JSON.parse('" + JSON . stringify ( collections ) . replace ( /['\\]/g , "\\$&" ) + "');\n"
+ " for (let o of json) {"
+ " var collection = new Zotero.Collection;\n"
+ " for (let field in o) { collection[field] = o[field]; }\n"
+ " collection.complete();\n"
+ " }\n"
+ " json = JSON.parse('" + JSON . stringify ( items ) . replace ( /['\\]/g , "\\$&" ) + "');\n"
+ " for (let o of json) {"
+ " var item = new Zotero.Item;\n"
+ " for (let field in o) { item[field] = o[field]; }\n"
+ " item.complete();\n"
+ " }\n"
+ "}"
) ) ;
yield translation . translate ( {
collections : [ collection . id ]
} ) ;
assert . lengthOf ( translation . newCollections , 1 ) ;
assert . isNumber ( translation . newCollections [ 0 ] . id ) ;
assert . lengthOf ( translation . newItems , 1 ) ;
assert . isNumber ( translation . newItems [ 0 ] . id ) ;
2021-01-25 08:14:20 +00:00
var childCollections = collection . getChildCollections ( true ) ;
2016-12-09 09:36:42 +00:00
assert . sameMembers ( childCollections , translation . newCollections . map ( c => c . id ) ) ;
} ) ;
} ) ;
describe ( "#_saveAttachment()" , function ( ) {
it ( "should save standalone attachment to collection" , function * ( ) {
var collection = yield createDataObject ( 'collection' ) ;
var items = [
{
itemType : "attachment" ,
title : "Test" ,
mimeType : "text/html" ,
url : "http://example.com"
}
] ;
var translation = new Zotero . Translate . Import ( ) ;
translation . setString ( "" ) ;
translation . setTranslator ( buildDummyTranslator (
"import" ,
"function detectImport() {}\n"
+ "function doImport() {\n"
+ " var json = JSON.parse('" + JSON . stringify ( items ) . replace ( /['\\]/g , "\\$&" ) + "');\n"
+ " for (var i=0; i<json.length; i++) {"
+ " var item = new Zotero.Item;\n"
+ " for (var field in json[i]) { item[field] = json[i][field]; }\n"
+ " item.complete();\n"
+ " }\n"
+ "}"
) ) ;
yield translation . translate ( {
collections : [ collection . id ]
} ) ;
assert . lengthOf ( translation . newItems , 1 ) ;
assert . isNumber ( translation . newItems [ 0 ] . id ) ;
assert . ok ( collection . hasItem ( translation . newItems [ 0 ] . id ) ) ;
} ) ;
2016-12-12 12:29:59 +00:00
} ) ;
describe ( '#saveItems' , function ( ) {
it ( "should deproxify item and attachment urls when proxy provided" , function * ( ) {
var itemID ;
var item = loadSampleData ( 'journalArticle' ) ;
item = item . journalArticle ;
item . url = 'https://www-example-com.proxy.example.com/' ;
item . attachments = [ {
url : 'https://www-example-com.proxy.example.com/pdf.pdf' ,
mimeType : 'application/pdf' ,
title : 'Example PDF' } ] ;
var itemSaver = new Zotero . Translate . ItemSaver ( {
libraryID : Zotero . Libraries . userLibraryID ,
attachmentMode : Zotero . Translate . ItemSaver . ATTACHMENT _MODE _FILE ,
2022-11-10 10:46:14 +00:00
proxy : new Zotero . Proxy ( { scheme : 'https://%h.proxy.example.com/%p' } )
2016-12-12 12:29:59 +00:00
} ) ;
var itemDeferred = Zotero . Promise . defer ( ) ;
var attachmentDeferred = Zotero . Promise . defer ( ) ;
itemSaver . saveItems ( [ item ] , Zotero . Promise . coroutine ( function * ( attachment , progressPercentage ) {
// ItemSaver returns immediately without waiting for attachments, so we use the callback
// to test attachments
if ( progressPercentage != 100 ) return ;
try {
yield itemDeferred . promise ;
let item = Zotero . Items . get ( itemID ) ;
attachment = Zotero . Items . get ( item . getAttachments ( ) [ 0 ] ) ;
assert . equal ( attachment . getField ( 'url' ) , 'https://www.example.com/pdf.pdf' ) ;
attachmentDeferred . resolve ( ) ;
} catch ( e ) {
attachmentDeferred . reject ( e ) ;
}
} ) ) . then ( function ( items ) {
try {
assert . equal ( items [ 0 ] . getField ( 'url' ) , 'https://www.example.com/' ) ;
itemID = items [ 0 ] . id ;
itemDeferred . resolve ( ) ;
} catch ( e ) {
itemDeferred . reject ( e ) ;
}
} ) ;
yield Zotero . Promise . all ( [ itemDeferred . promise , attachmentDeferred . promise ] ) ;
} ) ;
2016-12-09 09:36:42 +00:00
} ) ;
} ) ;
2017-03-03 09:09:37 +00:00
describe ( "Error Handling" , function ( ) {
it ( "should propagate saveItems() errors from synchronous doImport()" , function * ( ) {
var items = [
{
// Invalid object
} ,
{
itemType : "book" ,
title : "B"
}
] ;
var added = 0 ;
var notifierID = Zotero . Notifier . registerObserver ( {
notify : function ( event , type , ids , extraData ) {
added ++ ;
}
} , [ 'item' ] ) ;
var translation = new Zotero . Translate . Import ( ) ;
translation . setString ( "" ) ;
translation . setTranslator ( buildDummyTranslator (
"import" ,
"function detectImport() {}"
+ "function doImport() {"
+ " var json = JSON.parse('" + JSON . stringify ( items ) . replace ( /['\\]/g , "\\$&" ) + "');"
+ " for (let o of json) {"
+ " let item = new Zotero.Item;"
+ " for (let field in o) { item[field] = o[field]; }"
+ " item.complete();"
+ " }"
+ "}"
) ) ;
var e = yield getPromiseError ( translation . translate ( ) ) ;
Zotero . Notifier . unregisterObserver ( notifierID ) ;
assert . ok ( e ) ;
// Saving should be stopped without any saved items
assert . equal ( added , 0 ) ;
assert . equal ( translation . _savingItems , 0 ) ;
assert . equal ( translation . _runningAsyncProcesses , 0 ) ;
assert . isNull ( translation . _currentState ) ;
} ) ;
it ( "should propagate saveItems() errors from asynchronous doImport()" , function * ( ) {
var items = [
{
// Invalid object
} ,
{
itemType : "book" ,
title : "B"
}
] ;
var added = 0 ;
var notifierID = Zotero . Notifier . registerObserver ( {
notify : function ( event , type , ids , extraData ) {
added ++ ;
}
} , [ 'item' ] ) ;
var translation = new Zotero . Translate . Import ( ) ;
translation . setString ( "" ) ;
translation . setTranslator ( buildDummyTranslator (
"import" ,
"function detectImport() {}"
+ "function doImport() {"
+ " var json = JSON.parse('" + JSON . stringify ( items ) . replace ( /['\\]/g , "\\$&" ) + "');"
+ " return new Promise(function (resolve, reject) {"
+ " function next() {"
+ " var data = json.shift();"
+ " if (!data) {"
+ " resolve();"
+ " return;"
+ " }"
+ " var item = new Zotero.Item;"
+ " for (let field in data) { item[field] = data[field]; }"
+ " item.complete().then(next).catch(reject);"
+ " }"
+ " next();"
+ " });"
+ "}" ,
{
2017-07-05 19:25:57 +00:00
configOptions : {
async : true
}
2017-03-03 09:09:37 +00:00
}
) ) ;
var e = yield getPromiseError ( translation . translate ( ) ) ;
Zotero . Notifier . unregisterObserver ( notifierID ) ;
assert . ok ( e ) ;
// Saving should be stopped without any saved items
assert . equal ( added , 0 ) ;
assert . equal ( translation . _savingItems , 0 ) ;
assert . equal ( translation . _runningAsyncProcesses , 0 ) ;
assert . isNull ( translation . _currentState ) ;
} ) ;
it ( "should propagate errors from saveItems with synchronous doSearch()" , function * ( ) {
var stub = sinon . stub ( Zotero . Translate . ItemSaver . prototype , "saveItems" ) ;
stub . returns ( Zotero . Promise . reject ( new Error ( "Save error" ) ) ) ;
var translation = new Zotero . Translate . Search ( ) ;
translation . setTranslator ( buildDummyTranslator (
"search" ,
"function detectSearch() {}"
+ "function doSearch() {"
+ " var item = new Zotero.Item('journalArticle');"
+ " item.itemType = 'book';"
+ " item.title = 'A';"
+ " item.complete();"
+ "}"
) ) ;
translation . setSearch ( { itemType : "journalArticle" , DOI : "10.111/Test" } ) ;
var e = yield getPromiseError ( translation . translate ( {
libraryID : Zotero . Libraries . userLibraryID ,
saveAttachments : false
} ) ) ;
assert . ok ( e ) ;
stub . restore ( ) ;
} ) ;
it ( "should propagate errors from saveItems() with asynchronous doSearch()" , function * ( ) {
var stub = sinon . stub ( Zotero . Translate . ItemSaver . prototype , "saveItems" ) ;
stub . returns ( Zotero . Promise . reject ( new Error ( "Save error" ) ) ) ;
var translation = new Zotero . Translate . Search ( ) ;
translation . setTranslator ( buildDummyTranslator (
"search" ,
"function detectSearch() {}"
+ "function doSearch() {"
+ " var item = new Zotero.Item('journalArticle');"
+ " item.itemType = 'book';"
+ " item.title = 'A';"
+ " return new Promise(function (resolve, reject) {"
+ " item.complete().then(next).catch(reject);"
+ " });"
+ "}" ,
{
2017-07-05 19:25:57 +00:00
configOptions : {
async : true
}
2017-03-03 09:09:37 +00:00
}
) ) ;
translation . setSearch ( { itemType : "journalArticle" , DOI : "10.111/Test" } ) ;
var e = yield getPromiseError ( translation . translate ( {
libraryID : Zotero . Libraries . userLibraryID ,
saveAttachments : false
} ) ) ;
assert . ok ( e ) ;
stub . restore ( ) ;
} ) ;
} ) ;
2015-06-04 04:47:58 +00:00
} ) ;
2015-04-26 06:44:29 +00:00
describe ( "Zotero.Translate.ItemGetter" , function ( ) {
describe ( "nextItem" , function ( ) {
2015-06-01 03:59:15 +00:00
it ( 'should return false for an empty database' , Zotero . Promise . coroutine ( function * ( ) {
2015-04-26 06:44:29 +00:00
let getter = new Zotero . Translate . ItemGetter ( ) ;
2016-03-21 03:39:12 +00:00
assert . isFalse ( getter . nextItem ( ) ) ;
2015-06-01 03:59:15 +00:00
} ) ) ;
it ( 'should return items in order they are supplied' , Zotero . Promise . coroutine ( function * ( ) {
2015-04-26 06:44:29 +00:00
let getter = new Zotero . Translate . ItemGetter ( ) ;
2015-06-01 03:59:15 +00:00
let items , itemIDs , itemURIs ;
2020-07-05 10:20:01 +00:00
yield Zotero . DB . executeTransaction ( async function ( ) {
2015-06-01 03:59:15 +00:00
items = [
2020-07-05 10:20:01 +00:00
await new Zotero . Item ( 'journalArticle' ) ,
await new Zotero . Item ( 'book' )
2015-06-01 03:59:15 +00:00
] ;
2020-07-05 10:20:01 +00:00
itemIDs = [ await items [ 0 ] . save ( ) , await items [ 1 ] . save ( ) ] ;
2015-06-01 03:59:15 +00:00
itemURIs = items . map ( i => Zotero . URI . getItemURI ( i ) ) ;
} ) ;
2015-04-26 06:44:29 +00:00
getter . _itemsLeft = items ;
2016-03-21 03:39:12 +00:00
assert . equal ( ( getter . nextItem ( ) ) . uri , itemURIs [ 0 ] , 'first item comes out first' ) ;
assert . equal ( ( getter . nextItem ( ) ) . uri , itemURIs [ 1 ] , 'second item comes out second' ) ;
assert . isFalse ( ( getter . nextItem ( ) ) , 'end of item queue' ) ;
2015-06-01 03:59:15 +00:00
} ) ) ;
it ( 'should return items with tags in expected format' , Zotero . Promise . coroutine ( function * ( ) {
2015-04-26 06:44:29 +00:00
let getter = new Zotero . Translate . ItemGetter ( ) ;
2015-06-01 03:59:15 +00:00
let itemWithAutomaticTag , itemWithManualTag , itemWithMultipleTags
2015-04-26 06:44:29 +00:00
2020-07-05 10:20:01 +00:00
yield Zotero . DB . executeTransaction ( async function ( ) {
2015-06-01 03:59:15 +00:00
itemWithAutomaticTag = new Zotero . Item ( 'journalArticle' ) ;
itemWithAutomaticTag . addTag ( 'automatic tag' , 0 ) ;
2020-07-05 10:20:01 +00:00
await itemWithAutomaticTag . save ( ) ;
2015-06-01 03:59:15 +00:00
itemWithManualTag = new Zotero . Item ( 'journalArticle' ) ;
itemWithManualTag . addTag ( 'manual tag' , 1 ) ;
2020-07-05 10:20:01 +00:00
await itemWithManualTag . save ( ) ;
2015-06-01 03:59:15 +00:00
itemWithMultipleTags = new Zotero . Item ( 'journalArticle' ) ;
itemWithMultipleTags . addTag ( 'tag1' , 0 ) ;
itemWithMultipleTags . addTag ( 'tag2' , 1 ) ;
2020-07-05 10:20:01 +00:00
await itemWithMultipleTags . save ( ) ;
2015-06-01 03:59:15 +00:00
} ) ;
2015-04-26 06:44:29 +00:00
let legacyMode = [ false , true ] ;
for ( let i = 0 ; i < legacyMode . length ; i ++ ) {
getter . _itemsLeft = [ itemWithAutomaticTag , itemWithManualTag , itemWithMultipleTags ] ;
getter . legacy = legacyMode [ i ] ;
let suffix = legacyMode [ i ] ? ' in legacy mode' : '' ;
// itemWithAutomaticTag
2016-03-21 03:39:12 +00:00
let translatorItem = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isArray ( translatorItem . tags , 'item contains automatic tags in an array' + suffix ) ;
assert . isObject ( translatorItem . tags [ 0 ] , 'automatic tag is an object' + suffix ) ;
assert . equal ( translatorItem . tags [ 0 ] . tag , 'automatic tag' , 'automatic tag name provided as "tag" property' + suffix ) ;
if ( legacyMode [ i ] ) {
assert . equal ( translatorItem . tags [ 0 ] . type , 0 , 'automatic tag "type" is 0' + suffix ) ;
} else {
assert . isUndefined ( translatorItem . tags [ 0 ] . type , '"type" is undefined for automatic tag' + suffix ) ;
}
// itemWithManualTag
2016-03-21 03:39:12 +00:00
translatorItem = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isArray ( translatorItem . tags , 'item contains manual tags in an array' + suffix ) ;
assert . isObject ( translatorItem . tags [ 0 ] , 'manual tag is an object' + suffix ) ;
assert . equal ( translatorItem . tags [ 0 ] . tag , 'manual tag' , 'manual tag name provided as "tag" property' + suffix ) ;
assert . equal ( translatorItem . tags [ 0 ] . type , 1 , 'manual tag "type" is 1' + suffix ) ;
// itemWithMultipleTags
2016-03-21 03:39:12 +00:00
translatorItem = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isArray ( translatorItem . tags , 'item contains multiple tags in an array' + suffix ) ;
assert . lengthOf ( translatorItem . tags , 2 , 'expected number of tags returned' + suffix ) ;
}
2015-06-01 03:59:15 +00:00
} ) ) ;
it ( 'should return item collections in expected format' , Zotero . Promise . coroutine ( function * ( ) {
2015-04-26 06:44:29 +00:00
let getter = new Zotero . Translate . ItemGetter ( ) ;
2015-06-01 03:59:15 +00:00
let items , collections ;
2020-07-05 10:20:01 +00:00
yield Zotero . DB . executeTransaction ( async function ( ) {
2015-06-01 03:59:15 +00:00
items = getter . _itemsLeft = [
new Zotero . Item ( 'journalArticle' ) , // Not in collection
new Zotero . Item ( 'journalArticle' ) , // In a single collection
new Zotero . Item ( 'journalArticle' ) , //In two collections
new Zotero . Item ( 'journalArticle' ) // In a nested collection
] ;
2020-07-05 10:20:01 +00:00
await Zotero . Promise . all ( items . map ( item => item . save ( ) ) ) ;
2015-06-01 03:59:15 +00:00
collections = [
new Zotero . Collection ,
new Zotero . Collection ,
new Zotero . Collection ,
new Zotero . Collection
] ;
collections [ 0 ] . name = "test1" ;
collections [ 1 ] . name = "test2" ;
collections [ 2 ] . name = "subTest1" ;
collections [ 3 ] . name = "subTest2" ;
2020-07-05 10:20:01 +00:00
await collections [ 0 ] . save ( ) ;
await collections [ 1 ] . save ( ) ;
2015-06-01 03:59:15 +00:00
collections [ 2 ] . parentID = collections [ 0 ] . id ;
collections [ 3 ] . parentID = collections [ 1 ] . id ;
2020-07-05 10:20:01 +00:00
await collections [ 2 ] . save ( ) ;
await collections [ 3 ] . save ( ) ;
2015-06-01 03:59:15 +00:00
2020-07-05 10:20:01 +00:00
await collections [ 0 ] . addItems ( [ items [ 1 ] . id , items [ 2 ] . id ] ) ;
await collections [ 1 ] . addItem ( items [ 2 ] . id ) ;
await collections [ 2 ] . addItem ( items [ 3 ] . id ) ;
2015-06-01 03:59:15 +00:00
} ) ;
2015-04-26 06:44:29 +00:00
2016-03-21 03:39:12 +00:00
let translatorItem = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isArray ( translatorItem . collections , 'item in library root has a collections array' ) ;
assert . equal ( translatorItem . collections . length , 0 , 'item in library root does not list any collections' ) ;
2016-03-21 03:39:12 +00:00
translatorItem = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isArray ( translatorItem . collections , 'item in a single collection has a collections array' ) ;
assert . equal ( translatorItem . collections . length , 1 , 'item in a single collection lists one collection' ) ;
assert . equal ( translatorItem . collections [ 0 ] , collections [ 0 ] . key , 'item in a single collection identifies correct collection' ) ;
2016-03-21 03:39:12 +00:00
translatorItem = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isArray ( translatorItem . collections , 'item in two collections has a collections array' ) ;
assert . equal ( translatorItem . collections . length , 2 , 'item in two collections lists two collections' ) ;
assert . deepEqual (
translatorItem . collections . sort ( ) ,
[ collections [ 0 ] . key , collections [ 1 ] . key ] . sort ( ) ,
'item in two collections identifies correct collections'
) ;
2016-03-21 03:39:12 +00:00
translatorItem = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isArray ( translatorItem . collections , 'item in a nested collection has a collections array' ) ;
assert . equal ( translatorItem . collections . length , 1 , 'item in a single nested collection lists one collection' ) ;
assert . equal ( translatorItem . collections [ 0 ] , collections [ 2 ] . key , 'item in a single collection identifies correct collection' ) ;
2015-06-01 03:59:15 +00:00
} ) ) ;
2017-09-22 03:03:30 +00:00
it ( 'should return item relations in expected format' , Zotero . Promise . coroutine ( function * ( ) {
let getter = new Zotero . Translate . ItemGetter ( ) ;
let items ;
2015-04-26 06:44:29 +00:00
2020-07-05 10:20:01 +00:00
yield Zotero . DB . executeTransaction ( async function ( ) {
2017-09-22 03:03:30 +00:00
items = [
new Zotero . Item ( 'journalArticle' ) , // Item with no relations
new Zotero . Item ( 'journalArticle' ) , // Bidirectional relations
new Zotero . Item ( 'journalArticle' ) , // between these items
new Zotero . Item ( 'journalArticle' ) , // This item is related to two items below
new Zotero . Item ( 'journalArticle' ) , // But this item is not related to the item below
new Zotero . Item ( 'journalArticle' )
] ;
2020-07-05 10:20:01 +00:00
await Zotero . Promise . all ( items . map ( item => item . save ( ) ) ) ;
2015-06-01 03:59:15 +00:00
2020-07-05 10:20:01 +00:00
await items [ 1 ] . addRelatedItem ( items [ 2 ] ) ;
await items [ 2 ] . addRelatedItem ( items [ 1 ] ) ;
2015-06-01 03:59:15 +00:00
2020-07-05 10:20:01 +00:00
await items [ 3 ] . addRelatedItem ( items [ 4 ] ) ;
await items [ 4 ] . addRelatedItem ( items [ 3 ] ) ;
await items [ 3 ] . addRelatedItem ( items [ 5 ] ) ;
await items [ 5 ] . addRelatedItem ( items [ 3 ] ) ;
2017-09-22 03:03:30 +00:00
} ) ;
2015-06-01 03:59:15 +00:00
2017-09-22 03:03:30 +00:00
getter . _itemsLeft = items . slice ( ) ;
2015-06-01 03:59:15 +00:00
2017-09-22 03:03:30 +00:00
let translatorItem = getter . nextItem ( ) ;
assert . isObject ( translatorItem . relations , 'item with no relations has a relations object' ) ;
assert . equal ( Object . keys ( translatorItem . relations ) . length , 0 , 'item with no relations does not list any relations' ) ;
2015-06-01 03:59:15 +00:00
2017-09-22 03:03:30 +00:00
translatorItem = getter . nextItem ( ) ;
2015-06-01 03:59:15 +00:00
2017-09-22 03:03:30 +00:00
assert . isObject ( translatorItem . relations , 'item that is the subject of a single relation has a relations object' ) ;
assert . equal ( Object . keys ( translatorItem . relations ) . length , 1 , 'item that is the subject of a single relation lists one relations predicate' ) ;
assert . lengthOf ( translatorItem . relations [ 'dc:relation' ] , 1 , 'item that is the subject of a single relation lists one "dc:relation" object' ) ;
assert . equal ( translatorItem . relations [ 'dc:relation' ] [ 0 ] , Zotero . URI . getItemURI ( items [ 2 ] ) , 'item that is the subject of a single relation identifies correct object URI' ) ;
2015-06-01 03:59:15 +00:00
2017-09-22 03:03:30 +00:00
// We currently assign these bidirectionally above, so this is a bit redundant
translatorItem = getter . nextItem ( ) ;
assert . isObject ( translatorItem . relations , 'item that is the object of a single relation has a relations object' ) ;
assert . equal ( Object . keys ( translatorItem . relations ) . length , 1 , 'item that is the object of a single relation list one relations predicate' ) ;
assert . lengthOf ( translatorItem . relations [ 'dc:relation' ] , 1 , 'item that is the object of a single relation lists one "dc:relation" object' ) ;
assert . equal ( translatorItem . relations [ 'dc:relation' ] [ 0 ] , Zotero . URI . getItemURI ( items [ 1 ] ) , 'item that is the object of a single relation identifies correct subject URI' ) ;
translatorItem = getter . nextItem ( ) ;
assert . isObject ( translatorItem . relations , 'item that is the subject of two relations has a relations object' ) ;
assert . equal ( Object . keys ( translatorItem . relations ) . length , 1 , 'item that is the subject of two relations list one relations predicate' ) ;
assert . isDefined ( translatorItem . relations [ 'dc:relation' ] , 'item that is the subject of two relations uses "dc:relation" as the predicate' ) ;
assert . isArray ( translatorItem . relations [ 'dc:relation' ] , 'item that is the subject of two relations lists "dc:relation" object as an array' ) ;
assert . equal ( translatorItem . relations [ 'dc:relation' ] . length , 2 , 'item that is the subject of two relations lists two relations in the "dc:relation" array' ) ;
assert . deepEqual (
translatorItem . relations [ 'dc:relation' ] . sort ( ) ,
[ Zotero . URI . getItemURI ( items [ 4 ] ) , Zotero . URI . getItemURI ( items [ 5 ] ) ] . sort ( ) ,
'item that is the subject of two relations identifies correct object URIs'
) ;
2015-06-01 03:59:15 +00:00
2017-09-22 03:03:30 +00:00
translatorItem = getter . nextItem ( ) ;
assert . isObject ( translatorItem . relations , 'item that is the object of one relation from item with two relations has a relations object' ) ;
assert . equal ( Object . keys ( translatorItem . relations ) . length , 1 , 'item that is the object of one relation from item with two relations list one relations predicate' ) ;
assert . isDefined ( translatorItem . relations [ 'dc:relation' ] , 'item that is the object of one relation from item with two relations uses "dc:relation" as the predicate' ) ;
assert . lengthOf ( translatorItem . relations [ 'dc:relation' ] , 1 , 'item that is the object of one relation from item with two relations lists one "dc:relation" object' ) ;
assert . equal ( translatorItem . relations [ 'dc:relation' ] [ 0 ] , Zotero . URI . getItemURI ( items [ 3 ] ) , 'item that is the object of one relation from item with two relations identifies correct subject URI' ) ;
} ) ) ;
2015-06-01 03:59:15 +00:00
it ( 'should return standalone note in expected format' , Zotero . Promise . coroutine ( function * ( ) {
let relatedItem , note , collection ;
2020-07-05 10:20:01 +00:00
yield Zotero . DB . executeTransaction ( async function ( ) {
2015-06-01 03:59:15 +00:00
relatedItem = new Zotero . Item ( 'journalArticle' ) ;
2020-07-05 10:20:01 +00:00
await relatedItem . save ( ) ;
2015-06-01 03:59:15 +00:00
note = new Zotero . Item ( 'note' ) ;
note . setNote ( 'Note' ) ;
note . addTag ( 'automaticTag' , 0 ) ;
note . addTag ( 'manualTag' , 1 ) ;
2017-09-22 03:03:30 +00:00
note . addRelatedItem ( relatedItem ) ;
2020-07-05 10:20:01 +00:00
await note . save ( ) ;
2015-06-01 03:59:15 +00:00
2017-09-22 03:03:30 +00:00
relatedItem . addRelatedItem ( note ) ;
2020-07-05 10:20:01 +00:00
await relatedItem . save ( ) ;
2017-09-22 03:03:30 +00:00
2015-06-01 03:59:15 +00:00
collection = new Zotero . Collection ;
collection . name = 'test' ;
2020-07-05 10:20:01 +00:00
await collection . save ( ) ;
await collection . addItem ( note . id ) ;
2015-06-01 03:59:15 +00:00
} ) ;
2015-04-26 06:44:29 +00:00
let legacyMode = [ false , true ] ;
for ( let i = 0 ; i < legacyMode . length ; i ++ ) {
let getter = new Zotero . Translate . ItemGetter ( ) ;
getter . _itemsLeft = [ note ] ;
let legacy = getter . legacy = legacyMode [ i ] ;
let suffix = legacy ? ' in legacy mode' : '' ;
2016-03-21 03:39:12 +00:00
let translatorNote = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isDefined ( translatorNote , 'returns standalone note' + suffix ) ;
assert . equal ( translatorNote . itemType , 'note' , 'itemType is correct' + suffix ) ;
assert . equal ( translatorNote . note , 'Note' , 'note is correct' + suffix ) ;
assert . isString ( translatorNote . dateAdded , 'dateAdded is string' + suffix ) ;
assert . isString ( translatorNote . dateModified , 'dateModified is string' + suffix ) ;
if ( legacy ) {
assert . isTrue ( sqlDateTimeRe . test ( translatorNote . dateAdded ) , 'dateAdded is in correct format' + suffix ) ;
assert . isTrue ( sqlDateTimeRe . test ( translatorNote . dateModified ) , 'dateModified is in correct format' + suffix ) ;
assert . isNumber ( translatorNote . itemID , 'itemID is set' + suffix ) ;
assert . isString ( translatorNote . key , 'key is set' + suffix ) ;
} else {
assert . isTrue ( isoDateTimeRe . test ( translatorNote . dateAdded ) , 'dateAdded is in correct format' + suffix ) ;
assert . isTrue ( isoDateTimeRe . test ( translatorNote . dateModified ) , 'dateModified is in correct format' + suffix ) ;
}
// Tags
assert . isArray ( translatorNote . tags , 'contains tags as array' + suffix ) ;
assert . equal ( translatorNote . tags . length , 2 , 'contains correct number of tags' + suffix ) ;
let possibleTags = [
{ tag : 'automaticTag' , type : 0 } ,
{ tag : 'manualTag' , type : 1 }
] ;
for ( let i = 0 ; i < possibleTags . length ; i ++ ) {
let match = false ;
for ( let j = 0 ; j < translatorNote . tags . length ; j ++ ) {
if ( possibleTags [ i ] . tag == translatorNote . tags [ j ] . tag ) {
let type = possibleTags [ i ] . type ;
if ( ! legacy && type == 0 ) type = undefined ;
assert . equal ( translatorNote . tags [ j ] . type , type , possibleTags [ i ] . tag + ' tag is correct' + suffix ) ;
match = true ;
break ;
}
}
assert . isTrue ( match , 'has ' + possibleTags [ i ] . tag + ' tag ' + suffix ) ;
}
// Relations
2017-09-22 03:03:30 +00:00
assert . isObject ( translatorNote . relations , 'has relations as object' + suffix ) ;
assert . lengthOf ( translatorNote . relations [ 'dc:relation' ] , 1 , 'has one relation' + suffix ) ;
assert . equal ( translatorNote . relations [ 'dc:relation' ] [ 0 ] , Zotero . URI . getItemURI ( relatedItem ) , 'relation is correct' + suffix ) ;
2015-04-26 06:44:29 +00:00
if ( ! legacy ) {
// Collections
assert . isArray ( translatorNote . collections , 'has a collections array' + suffix ) ;
assert . equal ( translatorNote . collections . length , 1 , 'lists one collection' + suffix ) ;
assert . equal ( translatorNote . collections [ 0 ] , collection . key , 'identifies correct collection' + suffix ) ;
}
}
2015-06-01 03:59:15 +00:00
} ) ) ;
it ( 'should return attached note in expected format' , Zotero . Promise . coroutine ( function * ( ) {
let relatedItem , items , collection , note ;
2020-07-05 10:20:01 +00:00
yield Zotero . DB . executeTransaction ( async function ( ) {
2015-06-01 03:59:15 +00:00
relatedItem = new Zotero . Item ( 'journalArticle' ) ;
2020-07-05 10:20:01 +00:00
await relatedItem . save ( ) ;
2015-06-01 03:59:15 +00:00
items = [
new Zotero . Item ( 'journalArticle' ) ,
new Zotero . Item ( 'journalArticle' )
] ;
2020-07-05 10:20:01 +00:00
await Zotero . Promise . all ( items . map ( item => item . save ( ) ) ) ;
2015-06-01 03:59:15 +00:00
collection = new Zotero . Collection ;
collection . name = 'test' ;
2020-07-05 10:20:01 +00:00
await collection . save ( ) ;
await collection . addItem ( items [ 0 ] . id ) ;
await collection . addItem ( items [ 1 ] . id ) ;
2015-06-01 03:59:15 +00:00
note = new Zotero . Item ( 'note' ) ;
note . setNote ( 'Note' ) ;
note . addTag ( 'automaticTag' , 0 ) ;
note . addTag ( 'manualTag' , 1 ) ;
2020-07-05 10:20:01 +00:00
await note . save ( ) ;
2015-06-01 03:59:15 +00:00
2017-09-22 03:03:30 +00:00
note . addRelatedItem ( relatedItem ) ;
relatedItem . addRelatedItem ( note ) ;
2020-07-05 10:20:01 +00:00
await note . save ( ) ;
await relatedItem . save ( ) ;
2015-06-01 03:59:15 +00:00
} ) ;
2015-04-26 06:44:29 +00:00
let legacyMode = [ false , true ] ;
for ( let i = 0 ; i < legacyMode . length ; i ++ ) {
let item = items [ i ] ;
let getter = new Zotero . Translate . ItemGetter ( ) ;
getter . _itemsLeft = [ item ] ;
let legacy = getter . legacy = legacyMode [ i ] ;
let suffix = legacy ? ' in legacy mode' : '' ;
2016-03-21 03:39:12 +00:00
let translatorItem = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isArray ( translatorItem . notes , 'item with no notes contains notes array' + suffix ) ;
assert . equal ( translatorItem . notes . length , 0 , 'item with no notes contains empty notes array' + suffix ) ;
2015-06-01 03:59:15 +00:00
note . parentID = item . id ;
yield note . saveTx ( ) ;
2015-04-26 06:44:29 +00:00
getter = new Zotero . Translate . ItemGetter ( ) ;
getter . _itemsLeft = [ item ] ;
getter . legacy = legacy ;
2016-03-21 03:39:12 +00:00
translatorItem = getter . nextItem ( ) ;
2015-04-26 06:44:29 +00:00
assert . isArray ( translatorItem . notes , 'item with no notes contains notes array' + suffix ) ;
assert . equal ( translatorItem . notes . length , 1 , 'item with one note contains array with one note' + suffix ) ;
let translatorNote = translatorItem . notes [ 0 ] ;
assert . equal ( translatorNote . itemType , 'note' , 'itemType is correct' + suffix ) ;
assert . equal ( translatorNote . note , 'Note' , 'note is correct' + suffix ) ;
assert . isString ( translatorNote . dateAdded , 'dateAdded is string' + suffix ) ;
assert . isString ( translatorNote . dateModified , 'dateModified is string' + suffix ) ;
if ( legacy ) {
assert . isTrue ( sqlDateTimeRe . test ( translatorNote . dateAdded ) , 'dateAdded is in correct format' + suffix ) ;
assert . isTrue ( sqlDateTimeRe . test ( translatorNote . dateModified ) , 'dateModified is in correct format' + suffix ) ;
assert . isNumber ( translatorNote . itemID , 'itemID is set' + suffix ) ;
assert . isString ( translatorNote . key , 'key is set' + suffix ) ;
} else {
assert . isTrue ( isoDateTimeRe . test ( translatorNote . dateAdded ) , 'dateAdded is in correct format' + suffix ) ;
assert . isTrue ( isoDateTimeRe . test ( translatorNote . dateModified ) , 'dateModified is in correct format' + suffix ) ;
}
// Tags
assert . isArray ( translatorNote . tags , 'contains tags as array' + suffix ) ;
assert . equal ( translatorNote . tags . length , 2 , 'contains correct number of tags' + suffix ) ;
let possibleTags = [
{ tag : 'automaticTag' , type : 0 } ,
{ tag : 'manualTag' , type : 1 }
] ;
for ( let i = 0 ; i < possibleTags . length ; i ++ ) {
let match = false ;
for ( let j = 0 ; j < translatorNote . tags . length ; j ++ ) {
if ( possibleTags [ i ] . tag == translatorNote . tags [ j ] . tag ) {
let type = possibleTags [ i ] . type ;
if ( ! legacy && type == 0 ) type = undefined ;
assert . equal ( translatorNote . tags [ j ] . type , type , possibleTags [ i ] . tag + ' tag is correct' + suffix ) ;
match = true ;
break ;
}
}
assert . isTrue ( match , 'has ' + possibleTags [ i ] . tag + ' tag ' + suffix ) ;
}
// Relations
2017-09-22 03:03:30 +00:00
assert . isObject ( translatorNote . relations , 'has relations as object' + suffix ) ;
assert . lengthOf ( translatorNote . relations [ 'dc:relation' ] , 1 , 'has one relation' + suffix ) ;
assert . equal ( translatorNote . relations [ 'dc:relation' ] [ 0 ] , Zotero . URI . getItemURI ( relatedItem ) , 'relation is correct' + suffix ) ;
2015-04-26 06:44:29 +00:00
if ( ! legacy ) {
// Collections
2015-06-01 03:59:15 +00:00
assert . isUndefined ( translatorNote . collections , 'has no collections array' + suffix ) ;
2015-04-26 06:44:29 +00:00
}
}
2015-06-01 03:59:15 +00:00
} ) ) ;
2015-06-02 09:10:42 +00:00
2015-06-01 03:59:15 +00:00
it ( 'should return stored/linked file and URI attachments in expected format' , Zotero . Promise . coroutine ( function * ( ) {
this . timeout ( 60000 ) ;
2015-06-04 04:47:58 +00:00
let file = getTestPDF ( ) ;
2015-06-01 03:59:15 +00:00
let item , relatedItem ;
2015-04-26 06:44:29 +00:00
2020-07-05 10:20:01 +00:00
yield Zotero . DB . executeTransaction ( async function ( ) {
2015-06-01 03:59:15 +00:00
item = new Zotero . Item ( 'journalArticle' ) ;
2020-07-05 10:20:01 +00:00
await item . save ( ) ;
2015-06-01 03:59:15 +00:00
relatedItem = new Zotero . Item ( 'journalArticle' ) ;
2020-07-05 10:20:01 +00:00
await relatedItem . save ( ) ;
2015-06-01 03:59:15 +00:00
} ) ;
2015-04-26 06:44:29 +00:00
// Attachment items
let attachments = [
2015-06-01 03:59:15 +00:00
yield Zotero . Attachments . importFromFile ( { "file" : file } ) , // Standalone stored file
yield Zotero . Attachments . linkFromFile ( { "file" : file } ) , // Standalone link to file
yield Zotero . Attachments . importFromFile ( { "file" : file , "parentItemID" : item . id } ) , // Attached stored file
yield Zotero . Attachments . linkFromFile ( { "file" : file , "parentItemID" : item . id } ) , // Attached link to file
yield Zotero . Attachments . linkFromURL ( { "url" : 'http://example.com' , "parentItemID" : item . id , "contentType" : 'application/pdf' , "title" : 'empty.pdf' } ) // Attached link to URL
2015-04-26 06:44:29 +00:00
] ;
2020-07-05 10:20:01 +00:00
yield Zotero . DB . executeTransaction ( async function ( ) {
2015-06-01 03:59:15 +00:00
// Make sure all fields are populated
for ( let i = 0 ; i < attachments . length ; i ++ ) {
let attachment = attachments [ i ] ;
attachment . setField ( 'accessDate' , '2001-02-03 12:13:14' ) ;
2015-06-01 10:03:04 +00:00
attachment . attachmentCharset = 'utf-8' ;
2015-06-01 03:59:15 +00:00
attachment . setField ( 'url' , 'http://example.com' ) ;
attachment . setNote ( 'note' ) ;
attachment . addTag ( 'automaticTag' , 0 ) ;
attachment . addTag ( 'manualTag' , 1 ) ;
2017-09-22 03:03:30 +00:00
attachment . addRelatedItem ( relatedItem ) ;
2020-07-05 10:20:01 +00:00
await attachment . save ( ) ;
2017-09-22 03:03:30 +00:00
relatedItem . addRelatedItem ( attachment ) ;
2015-06-01 03:59:15 +00:00
}
2017-09-22 03:03:30 +00:00
2020-07-05 10:20:01 +00:00
await relatedItem . save ( ) ;
2015-06-01 03:59:15 +00:00
} ) ;
2015-04-26 06:44:29 +00:00
let items = [ attachments [ 0 ] , attachments [ 1 ] , item ] ; // Standalone attachments and item with child attachments
// Run tests
let legacyMode = [ false , true ] ;
for ( let i = 0 ; i < legacyMode . length ; i ++ ) {
let getter = new Zotero . Translate . ItemGetter ( ) ;
getter . _itemsLeft = items . slice ( ) ;
let exportDir = yield getTempDirectory ( ) ;
2019-08-25 10:51:11 +00:00
getter . _exportFileDirectory = Zotero . File . pathToFile ( exportDir ) ;
2015-04-26 06:44:29 +00:00
let legacy = getter . legacy = legacyMode [ i ] ;
let suffix = legacy ? ' in legacy mode' : '' ;
// Gather all standalone and child attachments into a single array,
// since tests are mostly the same
let translatorAttachments = [ ] , translatorItem ;
let itemsLeft = items . length , attachmentsLeft = attachments . length ;
2016-03-21 03:39:12 +00:00
while ( translatorItem = getter . nextItem ( ) ) {
2015-04-26 06:44:29 +00:00
assert . isString ( translatorItem . itemType , 'itemType is set' + suffix ) ;
// Standalone attachments
if ( translatorItem . itemType == 'attachment' ) {
translatorAttachments . push ( {
child : false ,
attachment : translatorItem
} ) ;
attachmentsLeft -- ;
// Child attachments
} else if ( translatorItem . itemType == 'journalArticle' ) {
assert . isArray ( translatorItem . attachments , 'item contains attachment array' + suffix ) ;
assert . equal ( translatorItem . attachments . length , 3 , 'attachment array contains all items' + suffix ) ;
for ( let i = 0 ; i < translatorItem . attachments . length ; i ++ ) {
let attachment = translatorItem . attachments [ i ] ;
assert . equal ( attachment . itemType , 'attachment' , 'item attachment is of itemType "attachment"' + suffix ) ;
translatorAttachments . push ( {
child : true ,
attachment : attachment
} ) ;
attachmentsLeft -- ;
}
// Unexpected
} else {
assert . fail ( translatorItem . itemType , 'attachment or journalArticle' , 'expected itemType returned' ) ;
}
itemsLeft -- ;
}
assert . equal ( itemsLeft , 0 , 'all items returned by getter' ) ;
assert . equal ( attachmentsLeft , 0 , 'all attachments returned by getter' ) ;
// Since we make no guarantees on the order of child attachments,
// we have to rely on URI as the identifier
let uriMap = { } ;
for ( let i = 0 ; i < attachments . length ; i ++ ) {
uriMap [ Zotero . URI . getItemURI ( attachments [ i ] ) ] = attachments [ i ] ;
}
for ( let j = 0 ; j < translatorAttachments . length ; j ++ ) {
let childAttachment = translatorAttachments [ j ] . child ;
let attachment = translatorAttachments [ j ] . attachment ;
assert . isString ( attachment . uri , 'uri is set' + suffix ) ;
let zoteroItem = uriMap [ attachment . uri ] ;
assert . isDefined ( zoteroItem , 'uri is correct' + suffix ) ;
delete uriMap [ attachment . uri ] ;
let storedFile = zoteroItem . attachmentLinkMode == Zotero . Attachments . LINK _MODE _IMPORTED _FILE
|| zoteroItem . attachmentLinkMode == Zotero . Attachments . LINK _MODE _IMPORTED _URL ;
let linkToURL = zoteroItem . attachmentLinkMode == Zotero . Attachments . LINK _MODE _LINKED _URL ;
let prefix = ( childAttachment ? 'attached ' : '' )
+ ( storedFile ? 'stored ' : 'link to ' )
+ ( linkToURL ? 'URL ' : 'file ' ) ;
// Set fields
assert . equal ( attachment . itemType , 'attachment' , prefix + 'itemType is correct' + suffix ) ;
assert . equal ( attachment . title , 'empty.pdf' , prefix + 'title is correct' + suffix ) ;
assert . equal ( attachment . url , 'http://example.com' , prefix + 'url is correct' + suffix ) ;
assert . equal ( attachment . note , 'note' , prefix + 'note is correct' + suffix ) ;
// Automatically set fields
assert . isString ( attachment . dateAdded , prefix + 'dateAdded is set' + suffix ) ;
assert . isString ( attachment . dateModified , prefix + 'dateModified is set' + suffix ) ;
// Legacy mode fields
if ( legacy ) {
assert . isNumber ( attachment . itemID , prefix + 'itemID is set' + suffix ) ;
assert . isString ( attachment . key , prefix + 'key is set' + suffix ) ;
assert . equal ( attachment . mimeType , 'application/pdf' , prefix + 'mimeType is correct' + suffix ) ;
assert . equal ( attachment . accessDate , '2001-02-03 12:13:14' , prefix + 'accessDate is correct' + suffix ) ;
assert . isTrue ( sqlDateTimeRe . test ( attachment . dateAdded ) , prefix + 'dateAdded matches SQL format' + suffix ) ;
assert . isTrue ( sqlDateTimeRe . test ( attachment . dateModified ) , prefix + 'dateModified matches SQL format' + suffix ) ;
} else {
assert . equal ( attachment . contentType , 'application/pdf' , prefix + 'contentType is correct' + suffix ) ;
assert . equal ( attachment . accessDate , '2001-02-03T12:13:14Z' , prefix + 'accessDate is correct' + suffix ) ;
assert . isTrue ( isoDateTimeRe . test ( attachment . dateAdded ) , prefix + 'dateAdded matches ISO-8601 format' + suffix ) ;
assert . isTrue ( isoDateTimeRe . test ( attachment . dateModified ) , prefix + 'dateModified matches ISO-8601 format' + suffix ) ;
}
if ( ! linkToURL ) {
// localPath
assert . isString ( attachment . localPath , prefix + 'localPath is set' + suffix ) ;
2019-08-25 10:51:11 +00:00
let attachmentFile = Zotero . File . pathToFile ( attachment . localPath ) ;
2015-04-26 06:44:29 +00:00
assert . isTrue ( attachmentFile . exists ( ) , prefix + 'localPath points to a file' + suffix ) ;
2015-06-01 10:03:04 +00:00
assert . isTrue ( attachmentFile . equals ( attachments [ j ] . getFile ( ) ) , prefix + 'localPath points to the correct file' + suffix ) ;
2015-04-26 06:44:29 +00:00
assert . equal ( attachment . filename , 'empty.pdf' , prefix + 'filename is correct' + suffix ) ;
assert . equal ( attachment . defaultPath , 'files/' + attachments [ j ] . id + '/' + attachment . filename , prefix + 'defaultPath is correct' + suffix ) ;
// saveFile function
assert . isFunction ( attachment . saveFile , prefix + 'has saveFile function' + suffix ) ;
2020-12-28 01:03:48 +00:00
yield attachment . saveFile ( attachment . defaultPath ) ;
2015-04-26 06:44:29 +00:00
assert . equal ( attachment . path , OS . Path . join ( exportDir , OS . Path . normalize ( attachment . defaultPath ) ) , prefix + 'path is set correctly after saveFile call' + suffix ) ;
let fileExists = yield OS . File . exists ( attachment . path ) ;
assert . isTrue ( fileExists , prefix + 'file was copied to the correct path by saveFile function' + suffix ) ;
fileExists = yield OS . File . exists ( attachment . localPath ) ;
assert . isTrue ( fileExists , prefix + 'file was not removed from original location' + suffix ) ;
2020-12-28 01:03:48 +00:00
let e ;
e = yield getPromiseError ( attachment . saveFile ( attachment . defaultPath ) ) ;
assert . match ( e . message , /^ERROR_FILE_EXISTS / , prefix + 'saveFile does not overwrite existing file by default' + suffix ) ;
e = yield getPromiseError ( attachment . saveFile ( 'file/../../' ) ) ;
assert . match ( e . message , /./ , prefix + 'saveFile does not allow exporting outside export directory' + suffix ) ;
2015-04-26 06:44:29 +00:00
/** TODO: check if overwriting existing file works **/
}
// Tags
assert . isArray ( attachment . tags , prefix + 'contains tags as array' + suffix ) ;
assert . equal ( attachment . tags . length , 2 , prefix + 'contains correct number of tags' + suffix ) ;
let possibleTags = [
{ tag : 'automaticTag' , type : 0 } ,
{ tag : 'manualTag' , type : 1 }
] ;
for ( let i = 0 ; i < possibleTags . length ; i ++ ) {
let match = false ;
for ( let j = 0 ; j < attachment . tags . length ; j ++ ) {
if ( possibleTags [ i ] . tag == attachment . tags [ j ] . tag ) {
let type = possibleTags [ i ] . type ;
if ( ! legacy && type == 0 ) type = undefined ;
assert . equal ( attachment . tags [ j ] . type , type , prefix + possibleTags [ i ] . tag + ' tag is correct' + suffix ) ;
match = true ;
break ;
}
}
assert . isTrue ( match , prefix + ' has ' + possibleTags [ i ] . tag + ' tag ' + suffix ) ;
}
// Relations
2017-09-22 03:03:30 +00:00
assert . isObject ( attachment . relations , prefix + 'has relations as object' + suffix ) ;
assert . lengthOf ( attachment . relations [ 'dc:relation' ] , 1 , prefix + 'has one relation' + suffix ) ;
assert . equal ( attachment . relations [ 'dc:relation' ] [ 0 ] , Zotero . URI . getItemURI ( relatedItem ) , prefix + 'relation is correct' + suffix ) ;
2015-04-26 06:44:29 +00:00
/** TODO: test other relations and multiple relations per predicate (should be an array) **/
}
}
} ) ) ;
} ) ;
2016-03-21 22:11:30 +00:00
describe ( "#setCollection()" , function ( ) {
it ( "should add collection items" , function * ( ) {
var col = yield createDataObject ( 'collection' ) ;
var item1 = yield createDataObject ( 'item' , { collections : [ col . id ] } ) ;
var item2 = yield createDataObject ( 'item' , { collections : [ col . id ] } ) ;
var item3 = yield createDataObject ( 'item' ) ;
let getter = new Zotero . Translate . ItemGetter ( ) ;
getter . setCollection ( col ) ;
assert . equal ( getter . numItems , 2 ) ;
} ) ;
} ) ;
2016-12-09 06:18:03 +00:00
2021-02-23 10:43:03 +00:00
describe ( "#setAll()" , function ( ) {
it ( "should exclude annotations" , async function ( ) {
var attachment = await importFileAttachment ( 'test.pdf' ) ;
var annotation = await createAnnotation ( 'highlight' , attachment ) ;
var getter = new Zotero . Translate . ItemGetter ( ) ;
await getter . setAll ( attachment . libraryID , false ) ;
var item ;
while ( item = getter . nextItem ( ) ) {
if ( item . itemType == 'annotation' ) {
assert . fail ( "Annotation item should not be returned from nextItem()" ) ;
break ;
}
}
} ) ;
} ) ;
2016-12-09 06:18:03 +00:00
describe ( "#_attachmentToArray()" , function ( ) {
it ( "should handle missing attachment files" , function * ( ) {
var item = yield importFileAttachment ( 'test.png' ) ;
var path = item . getFilePath ( ) ;
// Delete attachment file
yield OS . File . remove ( path ) ;
var translation = new Zotero . Translate . Export ( ) ;
var tmpDir = yield getTempDirectory ( ) ;
var exportDir = OS . Path . join ( tmpDir , 'export' ) ;
translation . setLocation ( Zotero . File . pathToFile ( exportDir ) ) ;
translation . setItems ( [ item ] ) ;
translation . setTranslator ( '14763d24-8ba0-45df-8f52-b8d1108e7ac9' ) ; // Zotero RDF
translation . setDisplayOptions ( {
exportFileData : true
} ) ;
yield translation . translate ( ) ;
var exportFile = OS . Path . join ( exportDir , 'export.rdf' ) ;
assert . isAbove ( ( yield OS . File . stat ( exportFile ) ) . size , 0 ) ;
} ) ;
2017-05-14 09:26:10 +00:00
it ( "should handle empty attachment path" , function * ( ) {
var item = yield importFileAttachment ( 'test.png' ) ;
item . _attachmentPath = '' ;
assert . equal ( item . attachmentPath , '' ) ;
var translation = new Zotero . Translate . Export ( ) ;
var tmpDir = yield getTempDirectory ( ) ;
var exportDir = OS . Path . join ( tmpDir , 'export' ) ;
translation . setLocation ( Zotero . File . pathToFile ( exportDir ) ) ;
translation . setItems ( [ item ] ) ;
translation . setTranslator ( '14763d24-8ba0-45df-8f52-b8d1108e7ac9' ) ; // Zotero RDF
translation . setDisplayOptions ( {
exportFileData : true
} ) ;
yield translation . translate ( ) ;
var exportFile = OS . Path . join ( exportDir , 'export.rdf' ) ;
assert . isAbove ( ( yield OS . File . stat ( exportFile ) ) . size , 0 ) ;
} ) ;
2019-01-12 07:34:31 +00:00
it ( "should handle UNC paths" , async function ( ) {
var path = '\\\\SHARE\\test.png' ;
var attachment = await Zotero . Attachments . linkFromFile ( {
file : OS . Path . join ( getTestDataDirectory ( ) . path , 'test.png' )
} ) ;
attachment . _attachmentPath = path ;
assert . equal ( attachment . attachmentPath , path ) ;
var translation = new Zotero . Translate . Export ( ) ;
var tmpDir = await getTempDirectory ( ) ;
var exportDir = OS . Path . join ( tmpDir , 'export' ) ;
translation . setLocation ( Zotero . File . pathToFile ( exportDir ) ) ;
translation . setItems ( [ attachment ] ) ;
translation . setTranslator ( '14763d24-8ba0-45df-8f52-b8d1108e7ac9' ) ; // Zotero RDF
translation . setDisplayOptions ( {
exportFileData : true
} ) ;
await translation . translate ( ) ;
var exportFile = OS . Path . join ( exportDir , 'export.rdf' ) ;
assert . isAbove ( ( await OS . File . stat ( exportFile ) ) . size , 0 ) ;
var rdf = Zotero . File . getContents ( exportFile ) ;
var dp = new DOMParser ( ) ;
var doc = dp . parseFromString ( rdf , 'text/xml' ) ;
assert . equal ( doc . querySelector ( 'resource' ) . getAttribute ( 'rdf:resource' ) , path ) ;
} ) ;
2016-12-09 06:18:03 +00:00
} ) ;
2015-06-04 04:47:58 +00:00
} ) ;
}