Add -g flag to runtests.sh to generate test data
Add functions to generate sample data for various formats * Zotero Web API JSON (Zotero.Item::toJSON) * CiteProc-JS JSON * Export translator JSON * Direct serialization of Zotero.Item fields Add a way to load sample data into DB from JSON Add tests for loading sample data into DB Add tests for automatically generated data This will help us make sure that field mappings and data formats don't change
This commit is contained in:
parent
9d5d8b525a
commit
2ebce91ecf
5 changed files with 593 additions and 24 deletions
|
@ -33,6 +33,9 @@ ZoteroUnit.prototype = {
|
|||
handle:function(cmdLine) {
|
||||
this.tests = cmdLine.handleFlagWithParam("test", false);
|
||||
this.noquit = cmdLine.handleFlag("noquit", false);
|
||||
this.makeTestData = cmdLine.handleFlag("makeTestData", false);
|
||||
this.noquit = !this.makeTestData && this.noquit;
|
||||
this.runTests = !this.makeTestData;
|
||||
},
|
||||
|
||||
dump:function(x) {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://zotero/q.js");
|
||||
var EventUtils = Components.utils.import("resource://zotero-unit/EventUtils.jsm");
|
||||
|
||||
var ZoteroUnit = Components.classes["@mozilla.org/commandlinehandler/general-startup;1?type=zotero-unit"].
|
||||
getService(Components.interfaces.nsISupports).
|
||||
wrappedJSObject;
|
||||
getService(Components.interfaces.nsISupports).
|
||||
wrappedJSObject;
|
||||
|
||||
var dump = ZoteroUnit.dump;
|
||||
|
||||
function quit(failed) {
|
||||
// Quit with exit status
|
||||
if(!failed) {
|
||||
OS.File.writeAtomic(FileUtils.getFile("ProfD", ["success"]).path, Uint8Array(0));
|
||||
OS.File.writeAtomic(OS.Path.join(OS.Constants.Path.profileDir, "success"), new Uint8Array(0));
|
||||
}
|
||||
if(!ZoteroUnit.noquit) {
|
||||
Components.classes['@mozilla.org/toolkit/app-startup;1'].
|
||||
|
@ -20,6 +20,72 @@ function quit(failed) {
|
|||
}
|
||||
}
|
||||
|
||||
if (ZoteroUnit.makeTestData) {
|
||||
let dataPath = getTestDataDirectory().path;
|
||||
|
||||
Zotero.Prefs.set("export.citePaperJournalArticleURL", true);
|
||||
|
||||
let dataFiles = [
|
||||
{
|
||||
name: 'allTypesAndFields',
|
||||
func: generateAllTypesAndFieldsData
|
||||
},
|
||||
{
|
||||
name: 'itemJSON',
|
||||
func: generateItemJSONData,
|
||||
args: [null]
|
||||
},
|
||||
{
|
||||
name: 'citeProcJSExport',
|
||||
func: generateCiteProcJSExportData
|
||||
},
|
||||
{
|
||||
name: 'translatorExportLegacy',
|
||||
func: generateTranslatorExportData,
|
||||
args: [true]
|
||||
},
|
||||
{
|
||||
name: 'translatorExport',
|
||||
func: generateTranslatorExportData,
|
||||
args: [false]
|
||||
}
|
||||
];
|
||||
let p = Q.resolve();
|
||||
for (let i=0; i<dataFiles.length; i++) {
|
||||
let first = !i;
|
||||
let params = dataFiles[i];
|
||||
|
||||
p = p.then(function() {
|
||||
// Make sure to not run next loop if previous fails
|
||||
return Q.try(function() {
|
||||
if (!first) dump('\n');
|
||||
dump('Generating data for ' + params.name + '...');
|
||||
|
||||
let filePath = OS.Path.join(dataPath, params.name + '.js');
|
||||
|
||||
return Q.resolve(OS.File.exists(filePath))
|
||||
.then(function(exists) {
|
||||
let currentData;
|
||||
if (exists) {
|
||||
currentData = loadSampleData(params.name);
|
||||
}
|
||||
|
||||
let args = params.args || [];
|
||||
args.push(currentData);
|
||||
let str = stableStringify(params.func.apply(null, args));
|
||||
|
||||
return OS.File.writeAtomic(OS.Path.join(dataPath, params.name + '.js'), str);
|
||||
});
|
||||
})
|
||||
.then(function() { dump("done."); })
|
||||
.catch(function(e) { dump("failed!"); throw e })
|
||||
});
|
||||
}
|
||||
|
||||
p.catch(function(e) { dump('\n'); dump(Zotero.Utilities.varDump(e)) })
|
||||
.finally(function() { quit(false) });
|
||||
}
|
||||
|
||||
function Reporter(runner) {
|
||||
var indents = 0, passed = 0, failed = 0;
|
||||
|
||||
|
@ -71,8 +137,8 @@ var assert = chai.assert,
|
|||
expect = chai.expect;
|
||||
|
||||
// Set up tests to run
|
||||
var run = true;
|
||||
if(ZoteroUnit.tests) {
|
||||
var run = ZoteroUnit.runTests;
|
||||
if(run && ZoteroUnit.tests) {
|
||||
var testDirectory = getTestDataDirectory().parent,
|
||||
testFiles = [];
|
||||
if(ZoteroUnit.tests == "all") {
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
// Useful "constants"
|
||||
var sqlDateTimeRe = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
|
||||
var isoDateTimeRe = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
|
||||
var zoteroObjectKeyRe = /^[23456789ABCDEFGHIJKMNPQRSTUVWXZ]{8}$/; // based on Zotero.Utilities::generateObjectKey()
|
||||
|
||||
/**
|
||||
* Waits for a DOM event on the specified node. Returns a promise
|
||||
* resolved with the event.
|
||||
|
@ -144,8 +149,8 @@ function installPDFTools() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a promise for the nsIFile corresponding to the test data
|
||||
* directory (i.e., test/tests/data)
|
||||
* Returns the nsIFile corresponding to the test data directory
|
||||
* (i.e., test/tests/data)
|
||||
*/
|
||||
function getTestDataDirectory() {
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
@ -168,3 +173,309 @@ function resetDB() {
|
|||
return Zotero.Schema.schemaUpdatePromise;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to JSON.stringify, except that object properties are stringified
|
||||
* in a sorted order.
|
||||
*/
|
||||
function stableStringify(obj, level, label) {
|
||||
if (!level) level = 0;
|
||||
let indent = '\t'.repeat(level);
|
||||
|
||||
if (label) label = JSON.stringify('' + label) + ': ';
|
||||
else label = '';
|
||||
|
||||
if (typeof obj == 'function' || obj === undefined) return null;
|
||||
|
||||
if (typeof obj != 'object' || obj === null) return indent + label + JSON.stringify(obj);
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
let str = indent + label + '[';
|
||||
for (let i=0; i<obj.length; i++) {
|
||||
let json = stableStringify(obj[i], level + 1);
|
||||
if (json === null) json = indent + '\tnull'; // function
|
||||
str += '\n' + json + (i < obj.length-1 ? ',' : '');
|
||||
}
|
||||
return str + (obj.length ? '\n' + indent : '') + ']';
|
||||
}
|
||||
|
||||
let keys = Object.keys(obj).sort(),
|
||||
empty = true,
|
||||
str = indent + label + '{';
|
||||
for (let i=0; i<keys.length; i++) {
|
||||
let json = stableStringify(obj[keys[i]], level + 1, keys[i]);
|
||||
if (json === null) continue; // function
|
||||
|
||||
empty = false;
|
||||
str += '\n' + json + (i < keys.length-1 ? ',' : '');
|
||||
}
|
||||
|
||||
return str + (!empty ? '\n' + indent : '') + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads specified sample data from file
|
||||
*/
|
||||
function loadSampleData(dataName) {
|
||||
let data = Zotero.File.getContentsFromURL('resource://zotero-unit-tests/data/' + dataName + '.js');
|
||||
return JSON.parse(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates sample item data that is stored in data/sampleItemData.js
|
||||
*/
|
||||
function generateAllTypesAndFieldsData() {
|
||||
let data = {};
|
||||
let itemTypes = Zotero.ItemTypes.getTypes();
|
||||
// For most fields, use the field name as the value, but this doesn't
|
||||
// work well for some fields that expect values in certain formats
|
||||
let specialValues = {
|
||||
date: '1999-12-31',
|
||||
filingDate: '2000-01-02',
|
||||
accessDate: '1997-06-13 23:59:58',
|
||||
number: 3,
|
||||
numPages: 4,
|
||||
issue: 5,
|
||||
volume: 6,
|
||||
numberOfVolumes: 7,
|
||||
edition: 8,
|
||||
seriesNumber: 9,
|
||||
ISBN: '978-1-234-56789-7',
|
||||
ISSN: '1234-5679',
|
||||
url: 'http://www.example.com',
|
||||
pages: '1-10',
|
||||
DOI: '10.1234/example.doi',
|
||||
runningTime: '1:22:33',
|
||||
language: 'en-US'
|
||||
};
|
||||
|
||||
// Item types that should not be included in sample data
|
||||
let excludeItemTypes = ['note', 'attachment'];
|
||||
|
||||
for (let i = 0; i < itemTypes.length; i++) {
|
||||
if (excludeItemTypes.indexOf(itemTypes[i].name) != -1) continue;
|
||||
|
||||
let itemFields = data[itemTypes[i].name] = {
|
||||
itemType: itemTypes[i].name
|
||||
};
|
||||
|
||||
let fields = Zotero.ItemFields.getItemTypeFields(itemTypes[i].id);
|
||||
for (let j = 0; j < fields.length; j++) {
|
||||
let field = fields[j];
|
||||
field = Zotero.ItemFields.getBaseIDFromTypeAndField(itemTypes[i].id, field) || field;
|
||||
|
||||
let name = Zotero.ItemFields.getName(field),
|
||||
value;
|
||||
|
||||
// Use field name as field value
|
||||
if (specialValues[name]) {
|
||||
value = specialValues[name];
|
||||
} else {
|
||||
value = name.charAt(0).toUpperCase() + name.substr(1);
|
||||
// Make it look nice (sentence case)
|
||||
value = value.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
.replace(/ [A-Z](?![A-Z])/g, m => m.toLowerCase()); // not all-caps words
|
||||
}
|
||||
|
||||
itemFields[name] = value;
|
||||
}
|
||||
|
||||
let creatorTypes = Zotero.CreatorTypes.getTypesForItemType(itemTypes[i].id),
|
||||
creators = itemFields.creators = [];
|
||||
for (let j = 0; j < creatorTypes.length; j++) {
|
||||
let typeName = creatorTypes[j].name;
|
||||
creators.push({
|
||||
creatorType: typeName,
|
||||
firstName: typeName + 'First',
|
||||
lastName: typeName + 'Last'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the database with sample items
|
||||
* The field values should be in the form exactly as they would appear in Zotero
|
||||
*/
|
||||
function populateDBWithSampleData(data) {
|
||||
Zotero.DB.beginTransaction();
|
||||
|
||||
for (let itemName in data) {
|
||||
let item = data[itemName];
|
||||
let zItem = new Zotero.Item(item.itemType);
|
||||
for (let itemField in item) {
|
||||
if (itemField == 'itemType') continue;
|
||||
|
||||
if (itemField == 'creators') {
|
||||
let creators = item[itemField];
|
||||
for (let i=0; i<creators.length; i++) {
|
||||
let creator = new Zotero.Creator();
|
||||
creator.firstName = creators[i].firstName;
|
||||
creator.lastName = creators[i].lastName;
|
||||
creator = Zotero.Creators.get(creator.save());
|
||||
|
||||
zItem.setCreator(i, creator, creators[i].creatorType);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (itemField == 'tags') {
|
||||
// Must save item first
|
||||
continue;
|
||||
}
|
||||
|
||||
zItem.setField(itemField, item[itemField]);
|
||||
}
|
||||
item.id = zItem.save();
|
||||
|
||||
if (item.tags && item.tags.length) {
|
||||
zItem = Zotero.Items.get(item.id);
|
||||
for (let i=0; i<item.tags.length; i++) {
|
||||
zItem.addTag(item.tags[i].tag, item.tags[i].type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.DB.commitTransaction();
|
||||
return data;
|
||||
}
|
||||
|
||||
function generateItemJSONData(options, currentData) {
|
||||
let items = populateDBWithSampleData(loadSampleData('allTypesAndFields')),
|
||||
jsonData = {};
|
||||
|
||||
for (let itemName in items) {
|
||||
let zItem = Zotero.Items.get(items[itemName].id);
|
||||
jsonData[itemName] = zItem.toJSON(options);
|
||||
|
||||
// Adjut accessDate so that it doesn't depend on computer time zone
|
||||
// Effectively, assume that current time zone is UTC
|
||||
if (jsonData[itemName].accessDate) {
|
||||
let date = Zotero.Date.isoToDate(jsonData[itemName].accessDate);
|
||||
date.setUTCMinutes(date.getUTCMinutes() - date.getTimezoneOffset());
|
||||
jsonData[itemName].accessDate = Zotero.Date.dateToISO(date);
|
||||
}
|
||||
|
||||
// Don't replace some fields that _always_ change (e.g. item keys)
|
||||
// as long as it follows expected format
|
||||
// This makes it easier to generate more meaningful diffs
|
||||
if (!currentData || !currentData[itemName]) continue;
|
||||
|
||||
for (let field in jsonData[itemName]) {
|
||||
let oldVal = currentData[itemName][field];
|
||||
if (!oldVal) continue;
|
||||
|
||||
let val = jsonData[itemName][field];
|
||||
switch (field) {
|
||||
case 'dateAdded':
|
||||
case 'dateModified':
|
||||
if (!isoDateTimeRe.test(oldVal) || !isoDateTimeRe.test(val)) continue;
|
||||
break;
|
||||
case 'key':
|
||||
if (!zoteroObjectKeyRe.test(oldVal) || !zoteroObjectKeyRe.test(val)) continue;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
jsonData[itemName][field] = oldVal;
|
||||
}
|
||||
}
|
||||
|
||||
return jsonData;
|
||||
}
|
||||
|
||||
function generateCiteProcJSExportData(currentData) {
|
||||
let items = populateDBWithSampleData(loadSampleData('allTypesAndFields')),
|
||||
cslExportData = {};
|
||||
|
||||
for (let itemName in items) {
|
||||
let zItem = Zotero.Items.get(items[itemName].id);
|
||||
cslExportData[itemName] = Zotero.Cite.System.prototype.retrieveItem(zItem);
|
||||
|
||||
// Don't replace id as long as it follows expected format
|
||||
if (!currentData || !currentData[itemName]) continue;
|
||||
|
||||
// For simplicity, be more lenient than for item key
|
||||
let idRe = /^http:\/\/zotero\.org\/users\/local\/\w{8}\/items\/\w{8}$/;
|
||||
for (let field in cslExportData[itemName]) {
|
||||
let oldVal = currentData[itemName][field];
|
||||
if (!oldVal) continue;
|
||||
|
||||
let val = cslExportData[itemName][field];
|
||||
switch (field) {
|
||||
case 'id':
|
||||
if (!idRe.test(oldVal) || !idRe.test(val)) continue;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
cslExportData[itemName][field] = oldVal;
|
||||
}
|
||||
}
|
||||
|
||||
return cslExportData;
|
||||
}
|
||||
|
||||
function generateTranslatorExportData(legacy, currentData) {
|
||||
let items = populateDBWithSampleData(loadSampleData('allTypesAndFields')),
|
||||
translatorExportData = {};
|
||||
|
||||
let itemGetter = new Zotero.Translate.ItemGetter();
|
||||
itemGetter.legacy = !!legacy;
|
||||
|
||||
for (let itemName in items) {
|
||||
let zItem = Zotero.Items.get(items[itemName].id);
|
||||
itemGetter._itemsLeft = [zItem];
|
||||
translatorExportData[itemName] = itemGetter.nextItem();
|
||||
|
||||
// Adjut ISO accessDate so that it doesn't depend on computer time zone
|
||||
// Effectively, assume that current time zone is UTC
|
||||
if (!legacy && translatorExportData[itemName].accessDate) {
|
||||
let date = Zotero.Date.isoToDate(translatorExportData[itemName].accessDate);
|
||||
date.setUTCMinutes(date.getUTCMinutes() - date.getTimezoneOffset());
|
||||
translatorExportData[itemName].accessDate = Zotero.Date.dateToISO(date);
|
||||
}
|
||||
|
||||
// Don't replace some fields that _always_ change (e.g. item keys)
|
||||
if (!currentData || !currentData[itemName]) continue;
|
||||
|
||||
// For simplicity, be more lenient than for item key
|
||||
let uriRe = /^http:\/\/zotero\.org\/users\/local\/\w{8}\/items\/\w{8}$/;
|
||||
let itemIDRe = /^\d+$/;
|
||||
for (let field in translatorExportData[itemName]) {
|
||||
let oldVal = currentData[itemName][field];
|
||||
if (!oldVal) continue;
|
||||
|
||||
let val = translatorExportData[itemName][field];
|
||||
switch (field) {
|
||||
case 'uri':
|
||||
if (!uriRe.test(oldVal) || !uriRe.test(val)) continue;
|
||||
break;
|
||||
case 'itemID':
|
||||
if (!itemIDRe.test(oldVal) || !itemIDRe.test(val)) continue;
|
||||
break;
|
||||
case 'key':
|
||||
if (!zoteroObjectKeyRe.test(oldVal) || !zoteroObjectKeyRe.test(val)) continue;
|
||||
break;
|
||||
case 'dateAdded':
|
||||
case 'dateModified':
|
||||
if (legacy) {
|
||||
if (!sqlDateTimeRe.test(oldVal) || !sqlDateTimeRe.test(val)) continue;
|
||||
} else {
|
||||
if (!isoDateTimeRe.test(oldVal) || !isoDateTimeRe.test(val)) continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
translatorExportData[itemName][field] = oldVal;
|
||||
}
|
||||
}
|
||||
|
||||
return translatorExportData;
|
||||
}
|
|
@ -15,36 +15,44 @@ function makePath {
|
|||
}
|
||||
|
||||
DEBUG=false
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
FX_EXECUTABLE="/Applications/Firefox.app/Contents/MacOS/firefox"
|
||||
else
|
||||
FX_EXECUTABLE="firefox"
|
||||
if [ -z "$FX_EXECUTABLE" ]; then
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
FX_EXECUTABLE="/Applications/Firefox.app/Contents/MacOS/firefox"
|
||||
else
|
||||
FX_EXECUTABLE="firefox"
|
||||
fi
|
||||
fi
|
||||
|
||||
FX_ARGS=""
|
||||
ZOTERO_ARGS=""
|
||||
|
||||
function usage {
|
||||
cat >&2 <<DONE
|
||||
Usage: $0 [-x FX_EXECUTABLE] [TESTS...]
|
||||
Usage: $0 [option] [TESTS...]
|
||||
Options
|
||||
-x FX_EXECUTABLE path to Firefox executable (default: $FX_EXECUTABLE)
|
||||
-d enable debug logging
|
||||
-c open JavaScript console and don't quit on completion
|
||||
-d enable debug logging
|
||||
-g generate test data and quit
|
||||
-x FX_EXECUTABLE path to Firefox executable (default: $FX_EXECUTABLE)
|
||||
TESTS set of tests to run (default: all)
|
||||
DONE
|
||||
exit 1
|
||||
}
|
||||
|
||||
while getopts "x:dc" opt; do
|
||||
while getopts "x:dcg" opt; do
|
||||
case $opt in
|
||||
x)
|
||||
FX_EXECUTABLE="$OPTARG"
|
||||
;;
|
||||
d)
|
||||
DEBUG=true
|
||||
;;
|
||||
c)
|
||||
FX_ARGS="-jsconsole -noquit"
|
||||
;;
|
||||
DEBUG=true
|
||||
;;
|
||||
c)
|
||||
FX_ARGS="-jsconsole -noquit"
|
||||
;;
|
||||
g)
|
||||
ZOTERO_ARGS="$ZOTERO_ARGS -makeTestData"
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
|
@ -87,13 +95,14 @@ if [ -z $IS_CYGWIN ]; then
|
|||
echo "`MOZ_NO_REMOTE=1 NO_EM_RESTART=1 \"$FX_EXECUTABLE\" -v`"
|
||||
fi
|
||||
|
||||
|
||||
if [ "$TRAVIS" = true ]; then
|
||||
FX_ARGS="$FX_ARGS --ZoteroNoUserInput"
|
||||
ZOTERO_ARGS="$ZOTERO_ARGS -ZoteroNoUserInput"
|
||||
fi
|
||||
|
||||
makePath FX_PROFILE "$PROFILE"
|
||||
MOZ_NO_REMOTE=1 NO_EM_RESTART=1 "$FX_EXECUTABLE" -profile "$FX_PROFILE" \
|
||||
-chrome chrome://zotero-unit/content/runtests.html -test "$TESTS" $FX_ARGS
|
||||
-chrome chrome://zotero-unit/content/runtests.html -test "$TESTS" $ZOTERO_ARGS $FX_ARGS
|
||||
|
||||
# Check for success
|
||||
test -e "$PROFILE/success"
|
||||
|
|
|
@ -9,4 +9,184 @@ describe("Support Functions for Unit Testing", function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe("loadSampleData", function() {
|
||||
it("should load data from file", function() {
|
||||
let data = loadSampleData('journalArticle');
|
||||
assert.isObject(data, 'loaded data object');
|
||||
assert.isNotNull(data);
|
||||
assert.isAbove(Object.keys(data).length, 0, 'data object is not empty');
|
||||
});
|
||||
});
|
||||
describe("populateDBWithSampleData", function() {
|
||||
it("should populate database with data", function() {
|
||||
let data = loadSampleData('journalArticle');
|
||||
populateDBWithSampleData(data);
|
||||
|
||||
let skipFields = ['id', 'itemType', 'creators']; // Special comparisons
|
||||
|
||||
for (let itemName in data) {
|
||||
let item = data[itemName];
|
||||
assert.isAbove(item.id, 0, 'assigned new item ID');
|
||||
|
||||
let zItem = Zotero.Items.get(item.id);
|
||||
assert.ok(zItem, 'inserted item into database');
|
||||
|
||||
// Compare item type
|
||||
assert.equal(item.itemType, Zotero.ItemTypes.getName(zItem.itemTypeID), 'inserted item has the same item type');
|
||||
|
||||
// Compare simple properties
|
||||
for (let prop in item) {
|
||||
if (skipFields.indexOf(prop) != -1) continue;
|
||||
|
||||
// Using base-mapped fields
|
||||
assert.equal(item[prop], zItem.getField(prop, false, true), 'inserted item property has the same value as sample data');
|
||||
}
|
||||
|
||||
if (item.creators) {
|
||||
// Compare creators
|
||||
for (let i=0; i<item.creators.length; i++) {
|
||||
let creator = item.creators[i];
|
||||
let zCreator = zItem.getCreator(i);
|
||||
assert.ok(zCreator, 'creator was added to item');
|
||||
assert.equal(creator.firstName, zCreator.ref.firstName, 'first names match');
|
||||
assert.equal(creator.lastName, zCreator.ref.lastName, 'last names match');
|
||||
assert.equal(creator.creatorType, Zotero.CreatorTypes.getName(zCreator.creatorTypeID), 'creator types match');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
it("should populate items with tags", function() {
|
||||
let data = populateDBWithSampleData({
|
||||
itemWithTags: {
|
||||
itemType: "journalArticle",
|
||||
tags: [
|
||||
{ tag: "automatic tag", type: 0 },
|
||||
{ tag: "manual tag", type: 1}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
let zItem = Zotero.Items.get(data.itemWithTags.id);
|
||||
assert.ok(zItem, 'inserted item with tags into database');
|
||||
|
||||
let tags = data.itemWithTags.tags;
|
||||
for (let i=0; i<tags.length; i++) {
|
||||
let tagID = Zotero.Tags.getID(tags[i].tag, tags[i].type);
|
||||
assert.ok(tagID, '"' + tags[i].tag + '" tag was inserted into the database');
|
||||
assert.ok(zItem.hasTag(tagID), '"' + tags[i].tag + '" tag was assigned to item');
|
||||
}
|
||||
});
|
||||
});
|
||||
describe("generateAllTypesAndFieldsData", function() {
|
||||
it("should generate all types and fields data", function() {
|
||||
let data = generateAllTypesAndFieldsData();
|
||||
assert.isObject(data, 'created data object');
|
||||
assert.isNotNull(data);
|
||||
assert.isAbove(Object.keys(data).length, 0, 'data object is not empty');
|
||||
});
|
||||
it("all types and fields sample data should be up to date", function() {
|
||||
assert.deepEqual(loadSampleData('allTypesAndFields'), generateAllTypesAndFieldsData());
|
||||
});
|
||||
});
|
||||
describe("generateItemJSONData", function() {
|
||||
it("item JSON data should be up to date", function() {
|
||||
let oldData = loadSampleData('itemJSON'),
|
||||
newData = generateItemJSONData();
|
||||
|
||||
assert.isObject(newData, 'created data object');
|
||||
assert.isNotNull(newData);
|
||||
assert.isAbove(Object.keys(newData).length, 0, 'data object is not empty');
|
||||
|
||||
// Ignore data that is not stable, but make sure it is set
|
||||
let ignoreFields = ['dateAdded', 'dateModified', 'key'];
|
||||
for (let itemName in oldData) {
|
||||
for (let i=0; i<ignoreFields.length; i++) {
|
||||
let field = ignoreFields[i]
|
||||
if (oldData[itemName][field] !== undefined) {
|
||||
assert.isDefined(newData[itemName][field], field + ' is set');
|
||||
delete oldData[itemName][field];
|
||||
delete newData[itemName][field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(oldData, newData);
|
||||
});
|
||||
});
|
||||
describe("generateCiteProcJSExportData", function() {
|
||||
let citeURL = Zotero.Prefs.get("export.citePaperJournalArticleURL");
|
||||
before(function () {
|
||||
Zotero.Prefs.set("export.citePaperJournalArticleURL", true);
|
||||
});
|
||||
after(function() {
|
||||
Zotero.Prefs.set("export.citePaperJournalArticleURL", citeURL);
|
||||
});
|
||||
|
||||
it("all citeproc-js export data should be up to date", function() {
|
||||
let oldData = loadSampleData('citeProcJSExport'),
|
||||
newData = generateCiteProcJSExportData();
|
||||
|
||||
assert.isObject(newData, 'created data object');
|
||||
assert.isNotNull(newData);
|
||||
assert.isAbove(Object.keys(newData).length, 0, 'citeproc-js export object is not empty');
|
||||
|
||||
// Ignore item ID
|
||||
for (let itemName in oldData) {
|
||||
delete oldData[itemName].id;
|
||||
}
|
||||
for (let itemName in newData) {
|
||||
delete newData[itemName].id;
|
||||
}
|
||||
|
||||
assert.deepEqual(oldData, newData, 'citeproc-js export data has not changed');
|
||||
});
|
||||
});
|
||||
describe("generateTranslatorExportData", function() {
|
||||
it("legacy mode data should be up to date", function() {
|
||||
let oldData = loadSampleData('translatorExportLegacy'),
|
||||
newData = generateTranslatorExportData(true);
|
||||
|
||||
assert.isObject(newData, 'created data object');
|
||||
assert.isNotNull(newData);
|
||||
assert.isAbove(Object.keys(newData).length, 0, 'translator export object is not empty');
|
||||
|
||||
// Ignore data that is not stable, but make sure it is set
|
||||
let ignoreFields = ['itemID', 'dateAdded', 'dateModified', 'uri', 'key'];
|
||||
for (let itemName in oldData) {
|
||||
for (let i=0; i<ignoreFields.length; i++) {
|
||||
let field = ignoreFields[i]
|
||||
if (oldData[itemName][field] !== undefined) {
|
||||
assert.isDefined(newData[itemName][field], field + ' is set');
|
||||
delete oldData[itemName][field];
|
||||
delete newData[itemName][field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(oldData, newData, 'translator export data has not changed');
|
||||
});
|
||||
it("data should be up to date", function() {
|
||||
let oldData = loadSampleData('translatorExport'),
|
||||
newData = generateTranslatorExportData();
|
||||
|
||||
assert.isObject(newData, 'created data object');
|
||||
assert.isNotNull(newData);
|
||||
assert.isAbove(Object.keys(newData).length, 0, 'translator export object is not empty');
|
||||
|
||||
// Ignore data that is not stable, but make sure it is set
|
||||
let ignoreFields = ['dateAdded', 'dateModified', 'uri'];
|
||||
for (let itemName in oldData) {
|
||||
for (let i=0; i<ignoreFields.length; i++) {
|
||||
let field = ignoreFields[i]
|
||||
if (oldData[itemName][field] !== undefined) {
|
||||
assert.isDefined(newData[itemName][field], field + ' is set');
|
||||
delete oldData[itemName][field];
|
||||
delete newData[itemName][field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(oldData, newData, 'translator export data has not changed');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue