- Ability to serialize and reload translator tests from translator tester (addresses #1842, Translator unit test automation)
- Fix a spacing issue in preferences
This commit is contained in:
parent
59066e40b7
commit
9f218caf75
2 changed files with 188 additions and 65 deletions
|
@ -26,12 +26,14 @@
|
|||
const NUM_CONCURRENT_TESTS = 6;
|
||||
const TRANSLATOR_TYPES = ["Web", "Import", "Export", "Search"];
|
||||
const TABLE_COLUMNS = ["Translator", "Supported", "Status", "Pending", "Succeeded", "Failed", "Unknown"];
|
||||
var translatorTables = {};
|
||||
var translatorTestViewsToRun = {};
|
||||
var translatorBox;
|
||||
var outputBox;
|
||||
var allOutputView;
|
||||
var currentOutputView;
|
||||
var translatorTables = {},
|
||||
translatorTestViews = {},
|
||||
translatorTestViewsToRun = {},
|
||||
translatorBox,
|
||||
outputBox,
|
||||
allOutputView,
|
||||
currentOutputView,
|
||||
viewerMode = true;
|
||||
|
||||
/**
|
||||
* Handles adding debug output to the output box
|
||||
|
@ -48,7 +50,7 @@ var OutputView = function(el) {
|
|||
*/
|
||||
OutputView.prototype.setDisplayed = function(isDisplayed) {
|
||||
this.isDisplayed = isDisplayed;
|
||||
if(this.isDisplayed) outputBox.textContent = this._output.join("\n\n");
|
||||
if(this.isDisplayed) outputBox.textContent = this._output.join("\n");
|
||||
if(this._el) this._el.className = (isDisplayed ? "output-displayed" : "output-hidden");
|
||||
currentOutputView = this;
|
||||
}
|
||||
|
@ -58,7 +60,14 @@ OutputView.prototype.setDisplayed = function(isDisplayed) {
|
|||
*/
|
||||
OutputView.prototype.addOutput = function(msg, level) {
|
||||
this._output.push(msg);
|
||||
if(this.isDisplayed) outputBox.textContent = this._output.join("\n\n");
|
||||
if(this.isDisplayed) outputBox.textContent = this._output.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets output to the output view
|
||||
*/
|
||||
OutputView.prototype.getOutput = function() {
|
||||
return this._output.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,21 +75,14 @@ OutputView.prototype.addOutput = function(msg, level) {
|
|||
* @constructor
|
||||
*/
|
||||
var TranslatorTestView = function(translator, type) {
|
||||
this._translator = translator;
|
||||
this._type = type;
|
||||
|
||||
var row = document.createElement("tr");
|
||||
var row = this._row = document.createElement("tr");
|
||||
|
||||
// Translator
|
||||
this._label = document.createElement("td");
|
||||
this._label.appendChild(document.createTextNode(translator.label));
|
||||
row.appendChild(this._label);
|
||||
|
||||
// Supported
|
||||
this._supported = document.createElement("td");
|
||||
var isSupported = translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER;
|
||||
this._supported.appendChild(document.createTextNode(isSupported ? "Yes" : "No"));
|
||||
this._supported.className = isSupported ? "supported-yes" : "supported-no";
|
||||
row.appendChild(this._supported);
|
||||
|
||||
// Status
|
||||
|
@ -103,12 +105,9 @@ var TranslatorTestView = function(translator, type) {
|
|||
this._unknown = document.createElement("td");
|
||||
row.appendChild(this._unknown);
|
||||
|
||||
// append to table
|
||||
translatorTables[type].appendChild(row);
|
||||
|
||||
// create output view and debug function
|
||||
var outputView = new OutputView(row);
|
||||
var debug = function(obj, msg, level) {
|
||||
var outputView = this._outputView = new OutputView(row);
|
||||
this._debug = function(obj, msg, level) {
|
||||
outputView.addOutput(msg, level);
|
||||
allOutputView.addOutput(msg, level);
|
||||
}
|
||||
|
@ -123,12 +122,62 @@ var TranslatorTestView = function(translator, type) {
|
|||
}, false);
|
||||
|
||||
// create translator tester and update status based on what it knows
|
||||
this._translatorTester = new Zotero_TranslatorTester(translator, type, debug);
|
||||
this.updateStatus(this._translatorTester);
|
||||
this.hasTests = !!this._translatorTester.tests.length;
|
||||
this.isRunning = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes TranslatorTestView given a translator and its type
|
||||
*/
|
||||
TranslatorTestView.prototype.initWithTranslatorAndType = function(translator, type) {
|
||||
this._label.appendChild(document.createTextNode(translator.label));
|
||||
|
||||
this.isSupported = translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER;
|
||||
this._supported.appendChild(document.createTextNode(this.isSupported ? "Yes" : "No"));
|
||||
this._supported.className = this.isSupported ? "supported-yes" : "supported-no";
|
||||
|
||||
this._translatorTester = new Zotero_TranslatorTester(translator, type, this._debug);
|
||||
this.canRun = !!this._translatorTester.tests.length;
|
||||
this.updateStatus(this._translatorTester);
|
||||
|
||||
this._type = type;
|
||||
translatorTables[this._type].appendChild(this._row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes TranslatorTestView given a JSON-ified translatorTester
|
||||
*/
|
||||
TranslatorTestView.prototype.unserialize = function(serializedData) {
|
||||
this._outputView.addOutput(serializedData.output);
|
||||
this._label.appendChild(document.createTextNode(serializedData.label));
|
||||
|
||||
this.isSupported = serializedData.isSupported;
|
||||
this._supported.appendChild(document.createTextNode(this.isSupported ? "Yes" : "No"));
|
||||
this._supported.className = this.isSupported ? "supported-yes" : "supported-no";
|
||||
|
||||
this._translatorTester = serializedData;
|
||||
this.canRun = false;
|
||||
this.updateStatus(this._translatorTester);
|
||||
|
||||
this._type = serializedData.type;
|
||||
translatorTables[this._type].appendChild(this._row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes TranslatorTestView given a JSON-ified translatorTester
|
||||
*/
|
||||
TranslatorTestView.prototype.serialize = function(serializedData) {
|
||||
return {
|
||||
"type":this._type,
|
||||
"output":this._outputView.getOutput(),
|
||||
"label":this._label.textContent,
|
||||
"isSupported":this.isSupported,
|
||||
"pending":this._translatorTester.pending,
|
||||
"failed":this._translatorTester.failed,
|
||||
"succeeded":this._translatorTester.succeeded,
|
||||
"unknown":this._translatorTester.unknown
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the displayed status of a translator
|
||||
*/
|
||||
|
@ -137,7 +186,7 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
|
|||
this._status.removeChild(this._status.firstChild);
|
||||
}
|
||||
|
||||
if(obj.tests.length) {
|
||||
if(obj.pending.length || obj.succeeded.length || obj.failed.length || obj.unknown.length) {
|
||||
if(obj.pending.length) {
|
||||
if(this.isRunning) {
|
||||
this._status.className = "status-running";
|
||||
|
@ -145,7 +194,7 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
|
|||
} else if(status && status === "pending") {
|
||||
this._status.className = "status-pending";
|
||||
this._status.textContent = "Pending";
|
||||
} else {
|
||||
} else if(this.canRun) {
|
||||
// show link to start
|
||||
var me = this;
|
||||
var a = document.createElement("a");
|
||||
|
@ -156,6 +205,8 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
|
|||
}, false);
|
||||
a.textContent = "Run";
|
||||
this._status.appendChild(a);
|
||||
} else {
|
||||
this._status.textContent = "Not Run";
|
||||
}
|
||||
} else if(obj.failed.length) {
|
||||
this._status.className = "status-failed";
|
||||
|
@ -203,7 +254,11 @@ TranslatorTestView.prototype.runTests = function(doneCallback) {
|
|||
/**
|
||||
* Called when loaded
|
||||
*/
|
||||
function load(event) {
|
||||
function load(event) {
|
||||
try {
|
||||
viewerMode = !Zotero;
|
||||
} catch(e) {};
|
||||
|
||||
if(window.chrome || window.safari) {
|
||||
// initialize injection
|
||||
Zotero.initInject();
|
||||
|
@ -253,22 +308,24 @@ function init() {
|
|||
var h1 = document.createElement("h1");
|
||||
h1.appendChild(document.createTextNode(displayType+" Translators "));
|
||||
|
||||
// create "run all"
|
||||
var runAll = document.createElement("a");
|
||||
runAll.href = "#";
|
||||
runAll.appendChild(document.createTextNode("(Run)"));
|
||||
runAll.addEventListener("click", new function() {
|
||||
var type = translatorType;
|
||||
return function(e) {
|
||||
e.preventDefault();
|
||||
for(var i in translatorTestViewsToRun[type]) {
|
||||
var testView = translatorTestViewsToRun[type][i];
|
||||
testView.updateStatus(testView._translatorTester, "pending");
|
||||
if(!viewerMode) {
|
||||
// create "run all"
|
||||
var runAll = document.createElement("a");
|
||||
runAll.href = "#";
|
||||
runAll.appendChild(document.createTextNode("(Run)"));
|
||||
runAll.addEventListener("click", new function() {
|
||||
var type = translatorType;
|
||||
return function(e) {
|
||||
e.preventDefault();
|
||||
for(var i in translatorTestViewsToRun[type]) {
|
||||
var testView = translatorTestViewsToRun[type][i];
|
||||
testView.updateStatus(testView._translatorTester, "pending");
|
||||
}
|
||||
runTranslatorTests(type);
|
||||
}
|
||||
runTranslatorTests(type);
|
||||
}
|
||||
}, false);
|
||||
h1.appendChild(runAll);
|
||||
}, false);
|
||||
h1.appendChild(runAll);
|
||||
}
|
||||
|
||||
translatorBox.appendChild(h1);
|
||||
|
||||
|
@ -290,24 +347,74 @@ function init() {
|
|||
translatorBox.appendChild(translatorTable);
|
||||
|
||||
// get translators, with code for unsupported translators
|
||||
Zotero.Translators.getAllForType(translatorType, new function() {
|
||||
var type = translatorType;
|
||||
return function(translators) {
|
||||
haveTranslators(translators, type);
|
||||
}
|
||||
}, true);
|
||||
if(!viewerMode) {
|
||||
Zotero.Translators.getAllForType(translatorType, new function() {
|
||||
var type = translatorType;
|
||||
return function(translators) {
|
||||
haveTranslators(translators, type);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
if(viewerMode) {
|
||||
// if no Zotero object, try to unserialize data
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", "testResults.json", true);
|
||||
req.overrideMimeType("text/plain");
|
||||
req.onreadystatechange = function(e) {
|
||||
if(req.readyState != 4) return;
|
||||
|
||||
if(req.responseText) { // success; unserialize
|
||||
var data = JSON.parse(req.responseText);
|
||||
for(var i=0, n=data.length; i<n; i++) {
|
||||
var translatorTestView = new TranslatorTestView();
|
||||
translatorTestView.unserialize(data[i]);
|
||||
}
|
||||
} else {
|
||||
jsonNotFound("XMLHttpRequest returned "+req.status);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
req.send();
|
||||
} catch(e) {
|
||||
jsonNotFound(e.toString());
|
||||
}
|
||||
} else {
|
||||
// create "serialize" link at bottom
|
||||
var lastP = document.createElement("p");
|
||||
var serialize = document.createElement("a");
|
||||
serialize.href = "#";
|
||||
serialize.appendChild(document.createTextNode("Serialize Results"));
|
||||
serialize.addEventListener("click", serializeAll, false);
|
||||
lastP.appendChild(serialize);
|
||||
translatorBox.appendChild(lastP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates no JSON file could be found.
|
||||
*/
|
||||
function jsonNotFound(str) {
|
||||
var body = document.body;
|
||||
while(body.hasChildNodes()) body.removeChild(body.firstChild);
|
||||
body.textContent = "testResults.json could not be loaded ("+str+").";
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after translators are returned from main script
|
||||
*/
|
||||
function haveTranslators(translators, type) {
|
||||
translatorTestViews[type] = [];
|
||||
translatorTestViewsToRun[type] = [];
|
||||
|
||||
for(var i in translators) {
|
||||
var translatorTestView = new TranslatorTestView(translators[i], type);
|
||||
if(translatorTestView.hasTests) {
|
||||
var translatorTestView = new TranslatorTestView();
|
||||
translatorTestView.initWithTranslatorAndType(translators[i], type);
|
||||
translatorTestViews[type].push(translatorTestView);
|
||||
if(translatorTestView.canRun) {
|
||||
translatorTestViewsToRun[type].push(translatorTestView);
|
||||
}
|
||||
}
|
||||
|
@ -325,4 +432,20 @@ function runTranslatorTests(type, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes all run translator tests
|
||||
*/
|
||||
function serializeAll(e) {
|
||||
var serializedData = [];
|
||||
for(var i in translatorTestViews) {
|
||||
var n = translatorTestViews[i].length;
|
||||
for(var j=0; j<n; j++) {
|
||||
serializedData.push(translatorTestViews[i][j].serialize());
|
||||
}
|
||||
}
|
||||
|
||||
document.location.href = "data:application/octet-stream,"+encodeURIComponent(JSON.stringify(serializedData, null, "\t"));
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
window.addEventListener("load", load, false);
|
|
@ -40,8 +40,8 @@ const Zotero_TranslatorTester_IGNORE_FIELDS = ["complete", "accessDate", "checkF
|
|||
* will be used.
|
||||
*/
|
||||
Zotero_TranslatorTester = function(translator, type, debug) {
|
||||
this._type = type;
|
||||
this._translator = translator;
|
||||
this.type = type;
|
||||
this.translator = translator;
|
||||
this._debug = debug ? debug : function(obj, a, b) { Zotero.debug(a, b) };
|
||||
|
||||
this.tests = [];
|
||||
|
@ -122,7 +122,7 @@ Zotero_TranslatorTester.prototype.setTests = function(tests) {
|
|||
Zotero_TranslatorTester.prototype.runTests = function(testDoneCallback, recursiveRun) {
|
||||
if(!recursiveRun) {
|
||||
var w = (this.pending.length === 1) ? " test" : " tests";
|
||||
this._debug(this, "TranslatorTester: Running "+this.pending.length+" "+w+" for "+this._translator.label);
|
||||
this._debug(this, "TranslatorTester: Running "+this.pending.length+" "+w+" for "+this.translator.label);
|
||||
}
|
||||
|
||||
if(!this.pending.length) {
|
||||
|
@ -144,13 +144,13 @@ Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallba
|
|||
var me = this;
|
||||
|
||||
var callback = function(obj, test, status, message) {
|
||||
me._debug(this, "TranslatorTester: "+me._translator.label+" Test "+testNumber+": "+status+" ("+message+")");
|
||||
me._debug(this, "TranslatorTester: "+me.translator.label+" Test "+testNumber+": "+status+" ("+message+")");
|
||||
me[status].push(test);
|
||||
if(testDoneCallback) testDoneCallback(me, test, status, message);
|
||||
me.runTests(testDoneCallback, true);
|
||||
};
|
||||
|
||||
if(this._type === "web") {
|
||||
if(this.type === "web") {
|
||||
this.fetchPageAndRunTest(test, callback);
|
||||
} else {
|
||||
this.runTest(test, null, callback);
|
||||
|
@ -190,13 +190,13 @@ Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function(test, testDoneC
|
|||
*/
|
||||
Zotero_TranslatorTester.prototype.runTest = function(test, doc, testDoneCallback) {
|
||||
var me = this;
|
||||
var translate = Zotero.Translate.newInstance(this._type);
|
||||
var translate = Zotero.Translate.newInstance(this.type);
|
||||
|
||||
if(this._type === "web") {
|
||||
if(this.type === "web") {
|
||||
translate.setDocument(doc);
|
||||
} else if(this._type === "import") {
|
||||
} else if(this.type === "import") {
|
||||
translate.setString(test.input);
|
||||
} else if(this._type === "search") {
|
||||
} else if(this.type === "search") {
|
||||
translate.setSearch(test.input);
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,7 @@ Zotero_TranslatorTester.prototype.runTest = function(test, doc, testDoneCallback
|
|||
translate.capitalizeTitles = false;
|
||||
|
||||
// internal hack to call detect on this translator
|
||||
translate._potentialTranslators = [this._translator];
|
||||
translate._potentialTranslators = [this.translator];
|
||||
translate._foundTranslators = [];
|
||||
translate._currentState = "detect";
|
||||
translate._detect();
|
||||
|
@ -246,14 +246,14 @@ Zotero_TranslatorTester.prototype._runTestTranslate = function(translate, transl
|
|||
if(!translators.length) {
|
||||
testDoneCallback(this, test, "failed", "Detection failed");
|
||||
return;
|
||||
} else if(this._type === "web" && (translators[0].itemType !== "multiple" && test.items.length > 1 ||
|
||||
} else if(this.type === "web" && (translators[0].itemType !== "multiple" && test.items.length > 1 ||
|
||||
test.items.length === 1 && translators[0].itemType !== test.items[0].itemType)) {
|
||||
// this handles "items":"multiple" too, since the string has length 8
|
||||
testDoneCallback(this, test, "failed", "Detection returned wrong item type");
|
||||
return;
|
||||
}
|
||||
|
||||
translate.setTranslator(this._translator);
|
||||
translate.setTranslator(this.translator);
|
||||
translate.translate(false);
|
||||
};
|
||||
|
||||
|
@ -305,9 +305,9 @@ Zotero_TranslatorTester.prototype.newTest = function(doc, testReadyCallback) {
|
|||
var multipleMode = false;
|
||||
|
||||
var me = this;
|
||||
var translate = Zotero.Translate.newInstance(this._type);
|
||||
var translate = Zotero.Translate.newInstance(this.type);
|
||||
translate.setDocument(doc);
|
||||
translate.setTranslator(this._translator);
|
||||
translate.setTranslator(this.translator);
|
||||
translate.setHandler("debug", this._debug);
|
||||
translate.setHandler("select", function(obj, items, callback) {
|
||||
multipleMode = true;
|
||||
|
@ -348,7 +348,7 @@ Zotero_TranslatorTester.prototype._createTest = function(translate, multipleMode
|
|||
var items = translate.newItems;
|
||||
}
|
||||
|
||||
testReadyCallback(this, {"type":this._type, "url":translate.document.location.href,
|
||||
testReadyCallback(this, {"type":this.type, "url":translate.document.location.href,
|
||||
"items":items});
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue