diff --git a/src/translation/translate.js b/src/translation/translate.js index 973637b..67ed34b 100644 --- a/src/translation/translate.js +++ b/src/translation/translate.js @@ -1113,7 +1113,7 @@ Zotero.Translate.Base.prototype = { if(t) promises.push(t); } if(!promises.length) return Zotero.Promise.reject(new Error("getTranslators: no valid translators were set")); - potentialTranslators = Zotero.Promise.all(promises); + potentialTranslators = Zotero.Promise.all(promises).then(val => [val]); } else { potentialTranslators = this._getTranslatorsGetPotentialTranslators(); } @@ -1720,6 +1720,16 @@ Zotero.Translate.Base.prototype = { if (returnValue !== undefined) this._returnValue = returnValue; this.decrementAsyncProcesses("Zotero.Translate#getTranslators"); + // If the translator started an async process in detect* (like loading another translator), + // wait for it in the promise we return + if (this._runningAsyncProcesses) { + return new Promise((resolve, reject) => { + this.setHandler('translators', () => resolve(this._returnValue)); + this.setHandler('error', (_, err) => reject(err)); + }); + } + + // Otherwise, immediately return what detect* returned return returnValue; }, @@ -1798,14 +1808,14 @@ Zotero.Translate.Base.prototype = { }.bind(this); if (this.noWait) { - let codePromise = Zotero.Translators.getCodeForTranslator(translator); + let codePromise = this._translatorProvider.getCodeForTranslator(translator); if (!codePromise.isResolved()) { throw new Error("Code promise is not resolved in noWait mode"); } parse(codePromise.value()); } else { - return Zotero.Translators.getCodeForTranslator(translator).then(parse); + return this._translatorProvider.getCodeForTranslator(translator).then(parse); } }), diff --git a/testTranslators/translatorTester.js b/testTranslators/translatorTester.js index 64bdaa9..9141a31 100644 --- a/testTranslators/translatorTester.js +++ b/testTranslators/translatorTester.js @@ -414,35 +414,41 @@ Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallba * @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) { +Zotero_TranslatorTester.prototype.fetchPageAndRunTest = async 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 + const { HiddenBrowser } = ChromeUtils.import("chrome://zotero/content/HiddenBrowser.jsm"); + const { RemoteTranslate } = ChromeUtils.import("chrome://zotero/content/RemoteTranslate.jsm"); + let browser = await HiddenBrowser.create(test.url, { + requireSuccessfulStatus: true, + docShell: { allowMetaRedirects: true } + }); + let translate = new RemoteTranslate(); + try { + if (test.defer) { + Zotero.debug("Waiting " + (Zotero_TranslatorTester.DEFER_DELAY / 1000) + + " second(s) for page content to settle"); + await Zotero.Promise.delay(Zotero_TranslatorTester.DEFER_DELAY); + } + else { + // Wait just a bit for things to settle + await Zotero.Promise.delay(100); + } + + await translate.setBrowser(browser); + await translate.setTranslatorProvider(this.translatorProvider); + translate.setTranslator(this.translator); + translate.setHandler("debug", (_, obj) => this._debug(this, obj)); + translate.setHandler("error", (_, err) => this._debug(this, err)); + let { test: newTest, status, message } = await translate.runTest(test); + translate.dispose(); + testDoneCallback(this, newTest, status, message); + } + finally { + HiddenBrowser.destroy(browser); + translate.dispose(); + } + return; } if (typeof process === 'object' && process + '' === '[object process]'){ @@ -609,6 +615,11 @@ Zotero_TranslatorTester.prototype._checkResult = function(test, translate, retur testDoneCallback(this, test, "failed", "Translation failed; examine debug output for errors"); return; } + + // Save items. This makes it easier to correct tests automatically. + test.itemsReturned = test.items === "multiple" + ? "multiple" + : translate.newItems.map(item => Zotero_TranslatorTester._sanitizeItem(item)); if(!translate.newItems.length) { testDoneCallback(this, test, "failed", "Translation failed: no items returned"); @@ -629,14 +640,6 @@ Zotero_TranslatorTester.prototype._checkResult = function(test, translate, retur // Show diff this._debug(this, "TranslatorTester: Data mismatch detected:"); this._debug(this, Zotero_TranslatorTester._generateDiff(testItem, translatedItem)); - - // Save items. This makes it easier to correct tests automatically. - var m = translate.newItems.length; - test.itemsReturned = new Array(m); - for(var j=0; j