diff --git a/chrome/content/scaffold/scaffold.js b/chrome/content/scaffold/scaffold.js index faf4435fc5..0682440f67 100644 --- a/chrome/content/scaffold/scaffold.js +++ b/chrome/content/scaffold/scaffold.js @@ -269,7 +269,7 @@ var Scaffold = new function() { } //Strip JSON metadata - var code = yield translator.getCode(); + var code = yield _translatorProvider.getCodeForTranslator(translator); var lastUpdatedIndex = code.indexOf('"lastUpdated"'); var header = code.substr(0, lastUpdatedIndex + 50); var m = /^\s*{[\S\s]*?}\s*?[\r\n]+/.exec(header); @@ -747,10 +747,6 @@ var Scaffold = new function() { translator[props[i]] = metadata[props[i]]; } - translator.getCode = function () { - return Zotero.Promise.resolve(this.code); - }; - if(!translator.configOptions) translator.configOptions = {}; if(!translator.displayOptions) translator.displayOptions = {}; if(!translator.browserSupport) translator.browserSupport = "g"; diff --git a/chrome/content/scaffold/scaffold.xul b/chrome/content/scaffold/scaffold.xul index 927d6feba7..ecc7d6e450 100644 --- a/chrome/content/scaffold/scaffold.xul +++ b/chrome/content/scaffold/scaffold.xul @@ -34,7 +34,7 @@ title="Scaffold" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - - - - Zotero Translator Tester - - - - \ No newline at end of file diff --git a/chrome/content/zotero/tools/testTranslators/testTranslators.js b/chrome/content/zotero/tools/testTranslators/testTranslators.js deleted file mode 100644 index c5e822df52..0000000000 --- a/chrome/content/zotero/tools/testTranslators/testTranslators.js +++ /dev/null @@ -1,653 +0,0 @@ -/* - ***** BEGIN LICENSE BLOCK ***** - - Copyright © 2011 Center for History and New Media - George Mason University, Fairfax, Virginia, USA - http://zotero.org - - This file is part of Zotero. - - Zotero is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Zotero is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Zotero. If not, see . - - ***** END LICENSE BLOCK ***** -*/ - -const NUM_CONCURRENT_TESTS = 6; -const TABLE_COLUMNS = ["Translator", "Supported", "Status", "Pending", "Succeeded", "Failed", "Mismatch", "Issues"]; -// Not using const to prevent const collisions in connectors -var TRANSLATOR_TYPES = ["Web", "Import", "Export", "Search"]; -var translatorTables = {}, - translatorTestViews = {}, - translatorTestViewsToRun = {}, - translatorTestStats = {}, - translatorBox, - outputBox, - allOutputView, - currentOutputView, - seleniumOutput = {}, - viewerMode = true; - -/** - * Fetches issue information from GitHub - */ -var Issues = new function() { - var _executeWhenRetrieved = []; - var githubInfo; - - /** - * Gets issues for a specific translator - * @param {String} translatorLabel Gets issues starting with translatorLabel - * @param {Function} callback Function to call when issue information is available - */ - this.getFor = function(translatorLabel, callback) { - translatorLabel = translatorLabel.toLowerCase(); - - var whenRetrieved = function() { - var issues = []; - for(var i=0; i { - let translatorType = displayType.toLowerCase(); - - translatorTestViews[translatorType] = []; - - // create header - var h1 = document.createElement("h1"); - h1.appendChild(document.createTextNode(displayType+" Translators ")); - - 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(); - runTranslatorTests(type); - } - }, false); - h1.appendChild(runAll); - } - - translatorBox.appendChild(h1); - - // create table - var translatorTable = document.createElement("table"); - translatorTables[translatorType] = translatorTable; - - translatorTestStats[translatorType] = new TranslatorTestStats(translatorType); - translatorBox.appendChild(translatorTestStats[translatorType].node); - - // add headings to table - var headings = document.createElement("tr"); - for(var j in TABLE_COLUMNS) { - var th = document.createElement("th"); - th.className = "th-"+TABLE_COLUMNS[j].toLowerCase(); - th.appendChild(document.createTextNode(TABLE_COLUMNS[j])); - headings.appendChild(th); - } - - // append to document - translatorTable.appendChild(headings); - translatorBox.appendChild(translatorTable); - - // get translators, with code for unsupported translators - if(!viewerMode) { - let translators = await Zotero.Translators.getAllForType(translatorType, true); - haveTranslators(translators, translatorType); - } - })); - - if(viewerMode) { - // if no Zotero object, try to unserialize data - var req = new XMLHttpRequest(); - var loc = "testResults.json"; - if(window.location.hash) { - var hashVars = {}; - var hashVarsSplit = window.location.hash.substr(1).split("&"); - for(var i=0; i { - translatorTestView.runTests(resolve); - }); - } - var elem = document.createElement('p'); - elem.setAttribute('id', 'translator-tests-complete'); - document.body.appendChild(elem); -} - -/** - * Begin running all translator tests of a given type - */ -function runTranslatorTests(type, callback) { - for(var i in translatorTestViewsToRun[type]) { - var testView = translatorTestViewsToRun[type][i]; - testView.updateStatus(testView._translatorTester, "pending"); - } - for(var i=0; i. - - ***** END LICENSE BLOCK ***** -*/ - -// Timeout for test to complete -var TEST_RUN_TIMEOUT = 15000; -var EXPORTED_SYMBOLS = ["Zotero_TranslatorTesters"]; - -// For debugging specific translators by label -var includeTranslators = []; - -if (typeof window != "undefined") { - window.Zotero = window.Zotero; -} else if (typeof global != 'undefined') { - global.Zotero = global.Zotero; -} else if (typeof this != 'undefined') { - this.Zotero = this.Zotero; -} - -var Zotero_TranslatorTesters = new function() { - const TEST_TYPES = ["web", "import", "export", "search"]; - var collectedResults = {}; - - /** - * Runs all tests - */ - this.runAllTests = function (numConcurrentTests, skipTranslators, writeDataCallback) { - var id = Math.random() * (100000000 - 1) + 1; - - if (!(typeof process === 'object' && process + '' === '[object process]')){ - waitForDialog(); - - if(!Zotero) { - Zotero = Components.classes["@zotero.org/Zotero;1"] - .getService(Components.interfaces.nsISupports).wrappedJSObject; - } - } - - var testers = []; - var waitingForTranslators = TEST_TYPES.length; - for(var i=0; i translators[i].label.includes(x))) continue; - if (skipTranslators && skipTranslators[translators[i].translatorID]) continue; - testers.push(new Zotero_TranslatorTester(translators[i], type)); - }; - - if(!(--waitingForTranslators)) { - runTesters(testers, numConcurrentTests, id, writeDataCallback); - } - } catch(e) { - Zotero.debug(e); - Zotero.logError(e); - } - }; - }); - }; - }; - - /** - * Runs a specific set of tests - */ - function runTesters(testers, numConcurrentTests, id, writeDataCallback) { - var testersRunning = 0; - var results = [] - - var testerDoneCallback = function(tester) { - try { - if(tester.pending.length) return; - - Zotero.debug("Done testing "+tester.translator.label); - - // Done translating, so serialize test results - testersRunning--; - let results = tester.serialize(); - let last = !testers.length && !testersRunning; - collectData(id, results, last, writeDataCallback); - - if(testers.length) { - // Run next tester if one is available - runNextTester(); - } - } catch(e) { - Zotero.debug(e); - Zotero.logError(e); - } - }; - - var runNextTester = function() { - if (!testers.length) { - return; - } - testersRunning++; - Zotero.debug("Testing "+testers[0].translator.label); - testers.shift().runTests(testerDoneCallback); - }; - - for(var i=0; i { - if (a.tag < b.tag) return -1; - if (b.tag < a.tag) return 1; - return 0; - }); - } - - return item; -}; -/** - * Serializes translator tester results to JSON - */ -Zotero_TranslatorTester.prototype.serialize = function() { - return { - "translatorID":this.translator.translatorID, - "type":this.type, - "output":this.output, - "label":this.translator.label, - "isSupported":this.isSupported, - "pending":this.pending, - "failed":this.failed, - "succeeded":this.succeeded, - "unknown":this.unknown - }; -}; - -/** - * Sets tests for this translatorTester - */ -Zotero_TranslatorTester.prototype.setTests = function(tests) { - this.tests = tests.slice(0); - this.pending = tests.slice(0); - this.succeeded = []; - this.failed = []; - this.unknown = []; -}; - -/** - * Executes tests for this translator - * @param {Function} testDoneCallback A callback to be executed each time a test is complete - */ -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); - } - - if(!this.pending.length) { - // always call testDoneCallback once if there are no tests - if(!recursiveRun && testDoneCallback) testDoneCallback(this, null, "unknown", "No tests present\n"); - return; - } - - this._runTestsRecursively(testDoneCallback); -}; - -/** - * Executes tests for this translator, without checks or a debug message - * @param {Function} testDoneCallback A callback to be executed each time a test is complete - */ -Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallback) { - var test = this.pending.shift(); - var testNumber = this.tests.length-this.pending.length; - var me = this; - - this._debug(this, "TranslatorTester: Running "+this.translator.label+" Test "+testNumber); - - var executedCallback = false; - var callback = function(obj, test, status, message) { - if(executedCallback) return; - executedCallback = true; - - me._debug(this, "TranslatorTester: "+me.translator.label+" Test "+testNumber+": "+status+" ("+message+")"); - me[status].push(test); - test.message = message; - if(testDoneCallback) testDoneCallback(me, test, status, message); - me.runTests(testDoneCallback, true); - }; - - if(this.type === "web") { - this.fetchPageAndRunTest(test, callback); - } else { - (Zotero.setTimeout ? Zotero : window).setTimeout(function() { - me.runTest(test, null, callback); - }, 0); - } - - (Zotero.setTimeout ? Zotero : window).setTimeout(function() { - callback(me, test, "failed", "Test timed out after "+TEST_RUN_TIMEOUT/1000+" seconds"); - }, TEST_RUN_TIMEOUT); -}; - -/** - * Fetches the page for a given test and runs it - * - * This function is only applicable in Firefox; it is overridden in translator_global.js in Chrome - * and Safari. - * - * @param {Object} test - Test to execute - * @param {Function} testDoneCallback - A callback to be executed when test is complete - */ -Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function (test, testDoneCallback) { - // Scaffold - if (Zotero.isFx) { - let browser = Zotero.HTTP.loadDocuments( - test.url, - (doc) => { - if (test.defer) { - Zotero.debug("Waiting " + (Zotero_TranslatorTester.DEFER_DELAY / 1000) - + " second(s) for page content to settle"); - } - setTimeout(() => { - // Use cookies from document in translator HTTP requests - this._cookieSandbox = new Zotero.CookieSandbox(null, test.url, doc.cookie); - - this.runTest(test, doc, function (obj, test, status, message) { - Zotero.Browser.deleteHiddenBrowser(browser); - testDoneCallback(obj, test, status, message); - }); - }, test.defer ? Zotero_TranslatorTester.DEFER_DELAY : 0); - }, - null, - (e) => { - Zotero.Browser.deleteHiddenBrowser(browser); - testDoneCallback(this, test, "failed", "Translation failed to initialize: " + e); - }, - true - ); - browser.docShell.allowMetaRedirects = true; - return - } - - if (typeof process === 'object' && process + '' === '[object process]'){ - this._cookieSandbox = require('request').jar(); - } - Zotero.HTTP.processDocuments( - test.url, - (doc) => { - this.runTest(test, doc, function (obj, test, status, message) { - testDoneCallback(obj, test, status, message); - }); - }, - { - cookieSandbox: this._cookieSandbox - } - ) - .catch(function (e) { - testDoneCallback(this, test, "failed", "Translation failed to initialize: " + e); - }.bind(this)) -}; - -/** - * Executes a test for a translator, given the document to test upon - * @param {Object} test Test to execute - * @param {Document} data DOM document to test against - * @param {Function} testDoneCallback A callback to be executed when test is complete - */ -Zotero_TranslatorTester.prototype.runTest = function(test, doc, testDoneCallback) { - this._debug(this, "TranslatorTester: Translating"+(test.url ? " "+test.url : "")); - - var me = this; - var translate = Zotero.Translate.newInstance(this.type); - if (this.translatorProvider) { - translate.setTranslatorProvider(this.translatorProvider); - } - if(this.type === "web") { - translate.setDocument(doc); - } else if(this.type === "import") { - translate.setString(test.input); - } else if(this.type === "search") { - translate.setSearch(test.input); - } - if (translate.setCookieSandbox && this._cookieSandbox) { - translate.setCookieSandbox(this._cookieSandbox); - } - - translate.setHandler("translators", function(obj, translators) { - me._runTestTranslate(translate, translators, test, testDoneCallback); - }); - translate.setHandler("debug", this._debug); - var errorReturned; - translate.setHandler("error", function(obj, err) { - errorReturned = err; - }); - translate.setHandler("done", function(obj, returnValue) { - me._checkResult(test, obj, returnValue, errorReturned, testDoneCallback); - }); - var selectCalled = false; - translate.setHandler("select", function(obj, items, callback) { - if(test.items !== "multiple" && test.items.length <= 1) { - testDoneCallback(me, test, "failed", "Zotero.selectItems() called, but only one item defined in test"); - callback({}); - return; - } else if(selectCalled) { - testDoneCallback(me, test, "failed", "Zotero.selectItems() called multiple times"); - callback({}); - return; - } - - selectCalled = true; - var newItems = {}; - var haveItems = false; - for(var i in items) { - if(items[i] && typeof(items[i]) == "object" && items[i].title !== undefined) { - newItems[i] = items[i].title; - } else { - newItems[i] = items[i]; - } - haveItems = true; - - // only save one item if "items":"multiple" (as opposed to an array of items) - if(test.items === "multiple") break; - } - - if(!haveItems) { - testDoneCallback(me, test, "failed", "No items defined"); - callback({}); - } - - callback(newItems); - }); - translate.capitalizeTitles = false; - - // internal hack to call detect on this translator - translate._potentialTranslators = [this.translator]; - translate._foundTranslators = []; - translate._currentState = "detect"; - translate._detect(); -} - -/** - * Runs translation for a translator, given a document to test against - */ -Zotero_TranslatorTester.prototype._runTestTranslate = function(translate, translators, test, testDoneCallback) { - if(!translators.length) { - testDoneCallback(this, test, "failed", "Detection failed"); - return; - } else if(this.type === "web" && translators[0].itemType !== Zotero.Translator.RUN_MODE_ZOTERO_SERVER - && (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.translate({ - libraryID: false - }); -}; - -/** - * Checks whether the results of translation match what is expected by the test - * @param {Object} test Test that was executed - * @param {Zotero.Translate} translate The Zotero.Translate instance - * @param {Boolean} returnValue Whether translation completed successfully - * @param {Error} error Error code, if one was specified - * @param {Function} testDoneCallback A callback to be executed when test is complete - */ -Zotero_TranslatorTester.prototype._checkResult = function(test, translate, returnValue, error, testDoneCallback) { - if(error) { - var errorString = "Translation failed: "+error.toString(); - if(typeof error === "object") { - for(var i in error) { - if(typeof(error[i]) != "object") { - errorString += "\n"+i+' => '+error[i]; - } - } - } - testDoneCallback(this, test, "failed", errorString); - return; - } - - if(!returnValue) { - testDoneCallback(this, test, "failed", "Translation failed; examine debug output for errors"); - return; - } - - if(!translate.newItems.length) { - testDoneCallback(this, test, "failed", "Translation failed: no items returned"); - return; - } - - if(test.items !== "multiple") { - if(translate.newItems.length !== test.items.length) { - testDoneCallback(this, test, "unknown", "Expected "+test.items.length+" items; got "+translate.newItems.length); - return; - } - - for(var i=0, n=test.items.length; i