Fix server_connector tests broken in 69ab4b0b

Don't display error prompt in standalone when style install fails.
Fixes an import bug when import input is invalid.
This commit is contained in:
Adomas Venčkauskas 2016-11-30 13:53:58 +02:00
parent 1b67ed071e
commit 45c944e731
5 changed files with 88 additions and 33 deletions

View File

@ -605,7 +605,7 @@ Zotero.Server.Connector.Import.prototype = {
translate.setString(data); translate.setString(data);
let translators = yield translate.getTranslators(); let translators = yield translate.getTranslators();
if (!translators || !translators.length) { if (!translators || !translators.length) {
return sendResponseCallback(404); return sendResponseCallback(400);
} }
translate.setTranslator(translators[0]); translate.setTranslator(translators[0]);
let items = yield translate.translate(); let items = yield translate.translate();
@ -628,7 +628,11 @@ Zotero.Server.Connector.InstallStyle.prototype = {
permitBookmarklet: false, permitBookmarklet: false,
init: Zotero.Promise.coroutine(function* (url, data, sendResponseCallback){ init: Zotero.Promise.coroutine(function* (url, data, sendResponseCallback){
let styleName = yield Zotero.Styles.install(data, url.query.origin || null, true); try {
var styleName = yield Zotero.Styles.install(data, url.query.origin || null, true);
} catch (e) {
sendResponseCallback(400, "text/plain", e.message)
}
sendResponseCallback(201, "application/json", JSON.stringify({name: styleName})); sendResponseCallback(201, "application/json", JSON.stringify({name: styleName}));
}) })
}; };

View File

@ -242,33 +242,42 @@ Zotero.Styles = new function() {
* containing the style data * containing the style data
* @param {String} origin The origin of the style, either a filename or URL, to be * @param {String} origin The origin of the style, either a filename or URL, to be
* displayed in dialogs referencing the style * displayed in dialogs referencing the style
* @param {Boolean} [noPrompt=false] Skip the confirmation prompt * @param {Boolean} [silent=false] Skip prompts
*/ */
this.install = Zotero.Promise.coroutine(function* (style, origin, noPrompt=false) { this.install = Zotero.Promise.coroutine(function* (style, origin, silent=false) {
var styleTitle; var styleTitle;
origin = origin || Zotero.getString('styles.unknownOrigin');
try { try {
if (style instanceof Components.interfaces.nsIFile) { if (style instanceof Components.interfaces.nsIFile) {
// handle nsIFiles // handle nsIFiles
var url = Services.io.newFileURI(style); var url = Services.io.newFileURI(style);
var xmlhttp = yield Zotero.HTTP.request("GET", url.spec); var xmlhttp = yield Zotero.HTTP.request("GET", url.spec);
styleTitle = yield _install(xmlhttp.responseText, style.leafName, false, noPrompt); styleTitle = yield _install(xmlhttp.responseText, style.leafName, false, silent);
} else { } else {
styleTitle = yield _install(style, origin, false, noPrompt); styleTitle = yield _install(style, origin, false, silent);
} }
} }
catch (error) { catch (error) {
// Unless user cancelled, show an alert with the error // Unless user cancelled, show an alert with the error
if(typeof error === "object" && error instanceof Zotero.Exception.UserCancelled) return; if(typeof error === "object" && error instanceof Zotero.Exception.UserCancelled) return;
if(typeof error === "object" && error instanceof Zotero.Exception.Alert) { if(typeof error === "object" && error instanceof Zotero.Exception.Alert) {
error.present();
error.log(); error.log();
if (silent) {
throw (error)
} else {
error.present();
}
} else { } else {
Zotero.logError(error); Zotero.logError(error);
if (silent) {
throw error
} else {
(new Zotero.Exception.Alert("styles.install.unexpectedError", (new Zotero.Exception.Alert("styles.install.unexpectedError",
origin, "styles.install.title", error)).present(); origin, "styles.install.title", error)).present();
} }
} }
}
return styleTitle; return styleTitle;
}); });
@ -278,10 +287,10 @@ Zotero.Styles = new function() {
* @param {String} origin The origin of the style, either a filename or URL, to be * @param {String} origin The origin of the style, either a filename or URL, to be
* displayed in dialogs referencing the style * displayed in dialogs referencing the style
* @param {Boolean} [hidden] Whether style is to be hidden. * @param {Boolean} [hidden] Whether style is to be hidden.
* @param {Boolean} [noPrompt=false] Skip the confirmation prompt * @param {Boolean} [silent=false] Skip prompts
* @return {Promise} * @return {Promise}
*/ */
var _install = Zotero.Promise.coroutine(function* (style, origin, hidden, noPrompt=false) { var _install = Zotero.Promise.coroutine(function* (style, origin, hidden, silent=false) {
if (!_initialized) yield Zotero.Styles.init(); if (!_initialized) yield Zotero.Styles.init();
var existingFile, destFile, source; var existingFile, destFile, source;
@ -364,7 +373,7 @@ Zotero.Styles = new function() {
// display a dialog to tell the user we're about to install the style // display a dialog to tell the user we're about to install the style
if(hidden) { if(hidden) {
destFile = destFileHidden; destFile = destFileHidden;
} else if (!noPrompt) { } else if (!silent) {
if(existingTitle) { if(existingTitle) {
var text = Zotero.getString('styles.updateStyle', [existingTitle, title, origin]); var text = Zotero.getString('styles.updateStyle', [existingTitle, title, origin]);
} else { } else {

View File

@ -1094,6 +1094,8 @@ Zotero.Translate.Base.prototype = {
if(this._currentState === "detect") throw new Error("getTranslators: detection is already running"); if(this._currentState === "detect") throw new Error("getTranslators: detection is already running");
this._currentState = "detect"; this._currentState = "detect";
this._getAllTranslators = getAllTranslators; this._getAllTranslators = getAllTranslators;
this._potentialTranslators = [];
this._foundTranslators = [];
if(checkSetTranslator) { if(checkSetTranslator) {
// setTranslator must be called beforehand if checkSetTranslator is set // setTranslator must be called beforehand if checkSetTranslator is set
@ -1123,8 +1125,6 @@ Zotero.Translate.Base.prototype = {
return potentialTranslators.then(function(result) { return potentialTranslators.then(function(result) {
var allPotentialTranslators = result[0]; var allPotentialTranslators = result[0];
var properToProxyFunctions = result[1]; var properToProxyFunctions = result[1];
this._potentialTranslators = [];
this._foundTranslators = [];
// this gets passed out by Zotero.Translators.getWebTranslatorsForLocation() because it is // this gets passed out by Zotero.Translators.getWebTranslatorsForLocation() because it is
// specific for each translator, but we want to avoid making a copy of a translator whenever // specific for each translator, but we want to avoid making a copy of a translator whenever
@ -1441,7 +1441,6 @@ Zotero.Translate.Base.prototype = {
var errorString = null; var errorString = null;
if(!returnValue && error) errorString = this._generateErrorString(error); if(!returnValue && error) errorString = this._generateErrorString(error);
if(this._currentState === "detect") { if(this._currentState === "detect") {
if(this._potentialTranslators.length) { if(this._potentialTranslators.length) {
var lastTranslator = this._potentialTranslators.shift(); var lastTranslator = this._potentialTranslators.shift();

View File

@ -832,6 +832,7 @@ styles.validationWarning = "%S" is not a valid CSL 1.0.1 style file, and may n
styles.installSourceError = %1$S references an invalid or non-existent CSL file at %2$S as its source. styles.installSourceError = %1$S references an invalid or non-existent CSL file at %2$S as its source.
styles.deleteStyle = Are you sure you want to delete the style "%1$S"? styles.deleteStyle = Are you sure you want to delete the style "%1$S"?
styles.deleteStyles = Are you sure you want to delete the selected styles? styles.deleteStyles = Are you sure you want to delete the selected styles?
styles.unknownOrigin = External Style
styles.abbreviations.title = Load Abbreviations styles.abbreviations.title = Load Abbreviations
styles.abbreviations.parseError = The abbreviations file "%1$S" is not valid JSON. styles.abbreviations.parseError = The abbreviations file "%1$S" is not valid JSON.

View File

@ -6,11 +6,13 @@ describe("Connector Server", function () {
var testServerPort = 16213; var testServerPort = 16213;
before(function* () { before(function* () {
this.timeout(20000);
Zotero.Prefs.set("httpServer.enabled", true); Zotero.Prefs.set("httpServer.enabled", true);
yield resetDB({ yield resetDB({
thisArg: this, thisArg: this,
skipBundledFiles: true skipBundledFiles: true
}); });
yield Zotero.Translators.init();
win = yield loadZoteroPane(); win = yield loadZoteroPane();
connectorServerPath = 'http://127.0.0.1:' + Zotero.Prefs.get('httpServer.port'); connectorServerPath = 'http://127.0.0.1:' + Zotero.Prefs.get('httpServer.port');
@ -314,30 +316,30 @@ describe("Connector Server", function () {
}); });
}); });
describe('/connector/importStyle', function() { describe('/connector/installStyle', function() {
var endpoint; var endpoint;
before(function() { before(function() {
endpoint = connectorServerPath + "/connector/importStyle"; endpoint = connectorServerPath + "/connector/installStyle";
}); });
it('should reject application/json requests', function* () { it('should reject styles with invalid text', function* () {
try { var error = yield getPromiseError(Zotero.HTTP.request(
var response = yield Zotero.HTTP.request(
'POST', 'POST',
endpoint, endpoint,
{ {
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: '{}' body: '{}'
} }
); ));
} catch(e) { assert.instanceOf(error, Zotero.HTTP.UnexpectedStatusException);
assert.instanceOf(e, Zotero.HTTP.UnexpectedStatusException); assert.equal(error.xmlhttp.status, 400);
assert.equal(e.xmlhttp.status, 400); assert.equal(error.xmlhttp.responseText,
} Zotero.getString("styles.installError",
Zotero.getString('styles.unknownOrigin')));
}); });
it('should import a style with text/x-csl content-type', function* () { it('should import a style with application/vnd.citationstyles.style+xml content-type', function* () {
sinon.stub(Zotero.Styles, 'install', function(style) { sinon.stub(Zotero.Styles, 'install', function(style) {
var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"] var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
.createInstance(Components.interfaces.nsIDOMParser), .createInstance(Components.interfaces.nsIDOMParser),
@ -362,7 +364,7 @@ describe("Connector Server", function () {
'POST', 'POST',
endpoint, endpoint,
{ {
headers: { "Content-Type": "text/x-csl" }, headers: { "Content-Type": "application/vnd.citationstyles.style+xml" },
body: style body: style
} }
); );
@ -371,4 +373,44 @@ describe("Connector Server", function () {
Zotero.Styles.install.restore(); Zotero.Styles.install.restore();
}); });
}); });
describe('/connector/import', function() {
var endpoint;
before(function() {
endpoint = connectorServerPath + "/connector/import";
});
it('should reject resources that do not contain import data', function* () {
var error = yield getPromiseError(Zotero.HTTP.request(
'POST',
endpoint,
{
headers: { "Content-Type": "text/plain" },
body: 'Owl'
}
));
assert.instanceOf(error, Zotero.HTTP.UnexpectedStatusException);
assert.equal(error.xmlhttp.status, 400);
});
it('should import resources (BibTeX)', function* () {
var resource = `@book{test1,
title={Test1},
author={Owl},
year={1000},
publisher={Curly Braces Publishing}
}`;
var response = yield Zotero.HTTP.request(
'POST',
endpoint,
{
headers: { "Content-Type": "application/x-bibtex" },
body: resource
}
);
assert.equal(response.status, 201);
assert.equal(JSON.parse(response.responseText)[0].title, 'Test1');
});
});
}); });