From 1c32db68dae445904f562ad7183d829ba56a0451 Mon Sep 17 00:00:00 2001 From: Simon Kornblith Date: Sat, 7 Mar 2015 12:18:27 -0500 Subject: [PATCH] Unit testing infrastructure Implements the beginnings of unit testing infrastructure using mocha/chai. The unit tests can be run locally using test/runtests.sh, although this will need tweaks to run on Windows. They should also run on commit using Travis-CI. The unit tests themselves live in test/tests. The index.js file specifies separate test sets, which can be run individually by calling test/runtests.sh . Right now there is only a single unit test, but hopefully we'll have more soon... --- .gitmodules | 6 +++ .travis.yml | 16 +++++++ test/chrome.manifest | 7 +++ test/components/zotero-unit.js | 51 ++++++++++++++++++++ test/content/runtests.html | 14 ++++++ test/content/runtests.js | 88 ++++++++++++++++++++++++++++++++++ test/install.rdf | 26 ++++++++++ test/resource/chai | 1 + test/resource/mocha | 1 + test/runtests.sh | 56 ++++++++++++++++++++++ test/tests/index.js | 3 ++ test/tests/utilities.js | 20 ++++++++ 12 files changed, 289 insertions(+) create mode 100644 .travis.yml create mode 100644 test/chrome.manifest create mode 100644 test/components/zotero-unit.js create mode 100644 test/content/runtests.html create mode 100644 test/content/runtests.js create mode 100644 test/install.rdf create mode 160000 test/resource/chai create mode 160000 test/resource/mocha create mode 100755 test/runtests.sh create mode 100644 test/tests/index.js create mode 100644 test/tests/utilities.js diff --git a/.gitmodules b/.gitmodules index 5000d9dc76..4eac6535f1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,9 @@ [submodule "styles"] path = styles url = git://github.com/zotero/bundled-styles.git +[submodule "test/resource/chai"] + path = test/resource/chai + url = https://github.com/chaijs/chai.git +[submodule "test/resource/mocha"] + path = test/resource/mocha + url = https://github.com/mochajs/mocha.git diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..4e03657774 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +language: cpp +compiler: + - gcc +env: + matrix: + - FIREFOXVERSION="36.0.1" + - FIREFOXVERSION="31.5.0esr" +notifications: + email: false +before_install: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + - wget http://ftp.mozilla.org/pub/firefox/releases/${FIREFOXVERSION}/linux-x86_64/en-US/firefox-${FIREFOXVERSION}.tar.bz2 + - tar -xjf firefox-${FIREFOXVERSION}.tar.bz2 +script: + - test/runtests.sh -x firefox/firefox diff --git a/test/chrome.manifest b/test/chrome.manifest new file mode 100644 index 0000000000..7885787e74 --- /dev/null +++ b/test/chrome.manifest @@ -0,0 +1,7 @@ +content zotero-unit content/ +resource zotero-unit resource/ +resource zotero-unit-tests tests/ + +component {b8570031-be5e-46e8-9785-38cd50a5d911} components/zotero-unit.js +contract @mozilla.org/commandlinehandler/general-startup;1?type=zotero-unit {b8570031-be5e-46e8-9785-38cd50a5d911} +category command-line-handler m-zotero-unit @mozilla.org/commandlinehandler/general-startup;1?type=zotero-unit diff --git a/test/components/zotero-unit.js b/test/components/zotero-unit.js new file mode 100644 index 0000000000..6b102c13df --- /dev/null +++ b/test/components/zotero-unit.js @@ -0,0 +1,51 @@ +"use strict"; +/* + ***** BEGIN LICENSE BLOCK ***** + + Copyright © 2012 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 ***** +*/ +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +function ZoteroUnit() { + this.wrappedJSObject = this; +} +ZoteroUnit.prototype = { + /* nsICommandLineHandler */ + handle:function(cmdLine) { + this.tests = cmdLine.handleFlagWithParam("test", false); + }, + + dump:function(x) { + dump(x); + }, + + contractID: "@mozilla.org/commandlinehandler/general-startup;1?type=zotero-unit", + classDescription: "Zotero Unit Command Line Handler", + classID: Components.ID("{b8570031-be5e-46e8-9785-38cd50a5d911}"), + service: true, + _xpcom_categories: [{category:"command-line-handler", entry:"m-zotero-unit"}], + QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsICommandLineHandler, + Components.interfaces.nsISupports]) +}; + + +var NSGetFactory = XPCOMUtils.generateNSGetFactory([ZoteroUnit]); diff --git a/test/content/runtests.html b/test/content/runtests.html new file mode 100644 index 0000000000..047e7a5e14 --- /dev/null +++ b/test/content/runtests.html @@ -0,0 +1,14 @@ + + + + Zotero Unit Tests + + + + + + + + + + \ No newline at end of file diff --git a/test/content/runtests.js b/test/content/runtests.js new file mode 100644 index 0000000000..aa0d6e8486 --- /dev/null +++ b/test/content/runtests.js @@ -0,0 +1,88 @@ +Components.utils.import("resource://gre/modules/FileUtils.jsm"); +Components.utils.import("resource://gre/modules/osfile.jsm") + +var ZoteroUnit = Components.classes["@mozilla.org/commandlinehandler/general-startup;1?type=zotero-unit"]. + 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)); + } + Components.classes['@mozilla.org/toolkit/app-startup;1']. + getService(Components.interfaces.nsIAppStartup). + quit(Components.interfaces.nsIAppStartup.eForceQuit); +} + +function Reporter(runner) { + var indents = 0, passed = 0, failed = 0; + + function indent() { + return Array(indents).join(' '); + } + + runner.on('start', function(){}); + + runner.on('suite', function(suite){ + ++indents; + dump(indent()+suite.title+"\n"); + }); + + runner.on('suite end', function(suite){ + --indents; + if (1 == indents) dump("\n"); + }); + + runner.on('pending', function(test){ + dump(indent()+"pending -"+test.title); + }); + + runner.on('pass', function(test){ + passed++; + var msg = "\r"+indent()+Mocha.reporters.Base.symbols.ok+" "+test.title; + if ('fast' != test.speed) { + msg += " ("+Math.round(test.duration)+" ms)"; + } + dump(msg+"\n"); + }); + + runner.on('fail', function(test, err){ + failed++; + dump("\r"+indent()+Mocha.reporters.Base.symbols.err+" "+test.title+"\n"); + }); + + runner.on('end', function() { + dump(passed+"/"+(passed+failed)+" tests passed.\n"); + quit(failed != 0); + }); +} + +// Setup Mocha +mocha.setup({ui:"bdd", reporter:Reporter}); +var assert = chai.assert, + expect = chai.expect; + +// Set up tests to run +if(ZoteroUnit.tests) { + document.body.appendChild(document.createTextNode("Running tests...")); + var torun = ZoteroUnit.tests == "all" ? Object.keys(TESTS) : ZoteroUnit.tests.split(","); + + for(var key of torun) { + if(!TESTS[key]) { + dump("Invalid test set "+torun+"\n"); + quit(true); + } + for(var test of TESTS[key]) { + var el = document.createElement("script"); + el.type = "application/javascript;version=1.8"; + el.src = "resource://zotero-unit-tests/"+test; + document.body.appendChild(el); + } + } +} + +window.onload = function() { + mocha.run(); +}; \ No newline at end of file diff --git a/test/install.rdf b/test/install.rdf new file mode 100644 index 0000000000..86dd153a3e --- /dev/null +++ b/test/install.rdf @@ -0,0 +1,26 @@ + + + + + + zotero-unit@zotero.org + Zotero Unit Tests + 1.0 + Center for History and New Media + Simon Kornblith + http://www.zotero.org + chrome://zotero/skin/zotero-new-z-48px.png + 2 + + + + + {ec8030f7-c20a-464f-9b0e-13a3a9e97384} + 31.0 + 38.* + + + + + diff --git a/test/resource/chai b/test/resource/chai new file mode 160000 index 0000000000..d7cafca023 --- /dev/null +++ b/test/resource/chai @@ -0,0 +1 @@ +Subproject commit d7cafca0232756f767275bb00e66930a7823b027 diff --git a/test/resource/mocha b/test/resource/mocha new file mode 160000 index 0000000000..65fc80ecd9 --- /dev/null +++ b/test/resource/mocha @@ -0,0 +1 @@ +Subproject commit 65fc80ecd96ca2159a792aff089bbc273d4bd86d diff --git a/test/runtests.sh b/test/runtests.sh new file mode 100755 index 0000000000..c31147f01a --- /dev/null +++ b/test/runtests.sh @@ -0,0 +1,56 @@ +#!/bin/bash +CWD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +if [ "`uname`" == "Darwin" ]; then + FX_EXECUTABLE="/Applications/Firefox.app/Contents/MacOS/firefox" +else + FX_EXECUTABLE="firefox" +fi + +function usage { + cat >&2 < "$PROFILE/extensions/zotero-unit@zotero.org" +echo "`dirname "$CWD"`" > "$PROFILE/extensions/zotero@chnm.gmu.edu" +echo 'user_pref("extensions.autoDisableScopes", 0);' > "$PROFILE/prefs.js" + +MOZ_NO_REMOTE=1 NO_EM_RESTART=1 "$FX_EXECUTABLE" -profile "$PROFILE" \ + -chrome chrome://zotero-unit/content/runtests.html -test "$TESTS" + +# Check for success +test -e "$PROFILE/success" +STATUS=$? + +# Clean up +rm -rf "$PROFILE" +exit $STATUS \ No newline at end of file diff --git a/test/tests/index.js b/test/tests/index.js new file mode 100644 index 0000000000..1252989560 --- /dev/null +++ b/test/tests/index.js @@ -0,0 +1,3 @@ +var TESTS = { + "utilities":["utilities.js"] +}; diff --git a/test/tests/utilities.js b/test/tests/utilities.js new file mode 100644 index 0000000000..b71dcb517c --- /dev/null +++ b/test/tests/utilities.js @@ -0,0 +1,20 @@ +describe("Zotero.Utilities", function() { + describe("cleanAuthor", function() { + it('should parse author names', function() { + for(let useComma of [false, true]) { + for(let first_expected of [["First", "First"], + ["First Middle", "First Middle"], + ["F. R. S.", "F. R. S."], + ["F.R.S.", "F. R. S."], + ["F R S", "F. R. S."], + ["FRS", "F. R. S."]]) { + let [first, expected] = first_expected; + let str = useComma ? "Last, "+first : first+" Last"; + let author = Zotero.Utilities.cleanAuthor(str, "author", useComma); + assert.equal(author.firstName, expected); + assert.equal(author.lastName, "Last"); + } + } + }); + }); +});