web staff: unit test structure; sample tests
authorBill Erickson <berick@esilibrary.com>
Thu, 12 Dec 2013 18:21:53 +0000 (13:21 -0500)
committerBill Erickson <berick@esilibrary.com>
Fri, 13 Dec 2013 14:00:53 +0000 (09:00 -0500)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
12 files changed:
Open-ILS/tests/staffweb/LICENSE.angular-seed [new file with mode: 0644]
Open-ILS/tests/staffweb/app/js [new symlink]
Open-ILS/tests/staffweb/config/karma.conf.js [new file with mode: 0644]
Open-ILS/tests/staffweb/scripts/e2e-test.bat [new file with mode: 0644]
Open-ILS/tests/staffweb/scripts/e2e-test.sh [new file with mode: 0755]
Open-ILS/tests/staffweb/scripts/test.bat [new file with mode: 0644]
Open-ILS/tests/staffweb/scripts/test.sh [new file with mode: 0755]
Open-ILS/tests/staffweb/scripts/watchr.rb [new file with mode: 0755]
Open-ILS/tests/staffweb/scripts/web-server.js [new file with mode: 0755]
Open-ILS/tests/staffweb/test/unit/egHomeApp.js [new file with mode: 0644]
Open-ILS/tests/staffweb/test/unit/egPatronApp.js [new file with mode: 0644]
Open-ILS/tests/staffweb/update-angular.sh [new file with mode: 0755]

diff --git a/Open-ILS/tests/staffweb/LICENSE.angular-seed b/Open-ILS/tests/staffweb/LICENSE.angular-seed
new file mode 100644 (file)
index 0000000..f2d3ff7
--- /dev/null
@@ -0,0 +1,22 @@
+The MIT License
+
+Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/Open-ILS/tests/staffweb/app/js b/Open-ILS/tests/staffweb/app/js
new file mode 120000 (symlink)
index 0000000..7f89b88
--- /dev/null
@@ -0,0 +1 @@
+../../../web/js/ui/default/staff
\ No newline at end of file
diff --git a/Open-ILS/tests/staffweb/config/karma.conf.js b/Open-ILS/tests/staffweb/config/karma.conf.js
new file mode 100644 (file)
index 0000000..4c657f3
--- /dev/null
@@ -0,0 +1,48 @@
+module.exports = function(config){
+    config.set({
+    basePath : '../',
+    //logLevel : config.LOG_DEBUG,
+
+    files : [
+      'app/lib/angular/angular.js',
+      'app/lib/angular/angular-*.js',
+      'app/lib/angular-ui-bootstrap/angular-bootstrap-min.js',
+      'test/lib/angular/angular-mocks.js',
+      'app/lib/opensrf/JSON_v1.js',
+      'app/lib/opensrf/md5.js',
+      'app/lib/opensrf/opensrf.js',
+      'app/lib/opensrf/opensrf_xhr.js',
+      'app/js/services/core.js',
+      'app/js/services/idl.js',
+      'app/js/services/event.js',
+      'app/js/services/net.js',
+      'app/js/services/auth.js',
+      'app/js/services/pcrud.js',
+      'app/js/services/env.js',
+      'app/js/services/org.js',
+      'app/js/services/user.js',
+      'app/js/services/startup.js',
+      'app/js/services/ui.js',
+      'app/js/**/*.js',
+      'test/unit/**/*.js'
+    ],
+
+    exclude : [
+      'app/lib/angular/angular-loader.js',
+      'app/lib/angular/*.min.js',
+      'app/lib/angular/angular-scenario.js'
+    ],
+
+    autoWatch : true,
+
+    frameworks: ['jasmine'],
+
+    browsers : ['Chrome'],
+
+    plugins : [
+            'karma-chrome-launcher',
+            'karma-firefox-launcher',
+            'karma-jasmine'
+            ],
+
+})}
diff --git a/Open-ILS/tests/staffweb/scripts/e2e-test.bat b/Open-ILS/tests/staffweb/scripts/e2e-test.bat
new file mode 100644 (file)
index 0000000..0b2aee6
--- /dev/null
@@ -0,0 +1,11 @@
+@echo off
+
+REM Windows script for running e2e tests
+REM You have to run server and capture some browser first
+REM
+REM Requirements:
+REM - NodeJS (http://nodejs.org/)
+REM - Karma (npm install -g karma)
+
+set BASE_DIR=%~dp0
+karma start "%BASE_DIR%\..\config\karma-e2e.conf.js" %*
diff --git a/Open-ILS/tests/staffweb/scripts/e2e-test.sh b/Open-ILS/tests/staffweb/scripts/e2e-test.sh
new file mode 100755 (executable)
index 0000000..47fe827
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+BASE_DIR=`dirname $0`
+
+echo ""
+echo "Starting Karma Server (http://karma-runner.github.io)"
+echo $BASE_DIR
+echo "-------------------------------------------------------------------"
+
+$BASE_DIR/../node_modules/karma/bin/karma start $BASE_DIR/../config/karma-e2e.conf.js $*
diff --git a/Open-ILS/tests/staffweb/scripts/test.bat b/Open-ILS/tests/staffweb/scripts/test.bat
new file mode 100644 (file)
index 0000000..6571f8f
--- /dev/null
@@ -0,0 +1,11 @@
+@echo off\r
+\r
+REM Windows script for running unit tests\r
+REM You have to run server and capture some browser first\r
+REM\r
+REM Requirements:\r
+REM - NodeJS (http://nodejs.org/)\r
+REM - Karma (npm install -g karma)\r
+\r
+set BASE_DIR=%~dp0\r
+karma start "%BASE_DIR%\..\config\karma.conf.js" %*\r
diff --git a/Open-ILS/tests/staffweb/scripts/test.sh b/Open-ILS/tests/staffweb/scripts/test.sh
new file mode 100755 (executable)
index 0000000..f6db762
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+BASE_DIR=`dirname $0`
+
+echo ""
+echo "Starting Karma Server (http://karma-runner.github.io)"
+echo "-------------------------------------------------------------------"
+
+#$BASE_DIR/../node_modules/karma/bin/karma start $BASE_DIR/../config/karma.conf.js $*
+karma start $BASE_DIR/../config/karma.conf.js $*
diff --git a/Open-ILS/tests/staffweb/scripts/watchr.rb b/Open-ILS/tests/staffweb/scripts/watchr.rb
new file mode 100755 (executable)
index 0000000..89ef656
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env watchr
+
+# config file for watchr http://github.com/mynyml/watchr
+# install: gem install watchr
+# run: watch watchr.rb
+# note: make sure that you have jstd server running (server.sh) and a browser captured
+
+log_file = File.expand_path(File.dirname(__FILE__) + '/../logs/jstd.log')
+
+`cd ..`
+`touch #{log_file}`
+
+puts "String watchr... log file: #{log_file}"
+
+watch( '(app/js|test/unit)' )  do
+  `echo "\n\ntest run started @ \`date\`" > #{log_file}`
+  `scripts/test.sh &> #{log_file}`
+end
+
diff --git a/Open-ILS/tests/staffweb/scripts/web-server.js b/Open-ILS/tests/staffweb/scripts/web-server.js
new file mode 100755 (executable)
index 0000000..3f74441
--- /dev/null
@@ -0,0 +1,244 @@
+#!/usr/bin/env node
+
+var util = require('util'),
+    http = require('http'),
+    fs = require('fs'),
+    url = require('url'),
+    events = require('events');
+
+var DEFAULT_PORT = 8000;
+
+function main(argv) {
+  new HttpServer({
+    'GET': createServlet(StaticServlet),
+    'HEAD': createServlet(StaticServlet)
+  }).start(Number(argv[2]) || DEFAULT_PORT);
+}
+
+function escapeHtml(value) {
+  return value.toString().
+    replace('<', '&lt;').
+    replace('>', '&gt;').
+    replace('"', '&quot;');
+}
+
+function createServlet(Class) {
+  var servlet = new Class();
+  return servlet.handleRequest.bind(servlet);
+}
+
+/**
+ * An Http server implementation that uses a map of methods to decide
+ * action routing.
+ *
+ * @param {Object} Map of method => Handler function
+ */
+function HttpServer(handlers) {
+  this.handlers = handlers;
+  this.server = http.createServer(this.handleRequest_.bind(this));
+}
+
+HttpServer.prototype.start = function(port) {
+  this.port = port;
+  this.server.listen(port);
+  util.puts('Http Server running at http://localhost:' + port + '/');
+};
+
+HttpServer.prototype.parseUrl_ = function(urlString) {
+  var parsed = url.parse(urlString);
+  parsed.pathname = url.resolve('/', parsed.pathname);
+  return url.parse(url.format(parsed), true);
+};
+
+HttpServer.prototype.handleRequest_ = function(req, res) {
+  var logEntry = req.method + ' ' + req.url;
+  if (req.headers['user-agent']) {
+    logEntry += ' ' + req.headers['user-agent'];
+  }
+  util.puts(logEntry);
+  req.url = this.parseUrl_(req.url);
+  var handler = this.handlers[req.method];
+  if (!handler) {
+    res.writeHead(501);
+    res.end();
+  } else {
+    handler.call(this, req, res);
+  }
+};
+
+/**
+ * Handles static content.
+ */
+function StaticServlet() {}
+
+StaticServlet.MimeMap = {
+  'txt': 'text/plain',
+  'html': 'text/html',
+  'css': 'text/css',
+  'xml': 'application/xml',
+  'json': 'application/json',
+  'js': 'application/javascript',
+  'jpg': 'image/jpeg',
+  'jpeg': 'image/jpeg',
+  'gif': 'image/gif',
+  'png': 'image/png',
+  'svg': 'image/svg+xml'
+};
+
+StaticServlet.prototype.handleRequest = function(req, res) {
+  var self = this;
+  var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
+    return String.fromCharCode(parseInt(hex, 16));
+  });
+  var parts = path.split('/');
+  if (parts[parts.length-1].charAt(0) === '.')
+    return self.sendForbidden_(req, res, path);
+  fs.stat(path, function(err, stat) {
+    if (err)
+      return self.sendMissing_(req, res, path);
+    if (stat.isDirectory())
+      return self.sendDirectory_(req, res, path);
+    return self.sendFile_(req, res, path);
+  });
+}
+
+StaticServlet.prototype.sendError_ = function(req, res, error) {
+  res.writeHead(500, {
+      'Content-Type': 'text/html'
+  });
+  res.write('<!doctype html>\n');
+  res.write('<title>Internal Server Error</title>\n');
+  res.write('<h1>Internal Server Error</h1>');
+  res.write('<pre>' + escapeHtml(util.inspect(error)) + '</pre>');
+  util.puts('500 Internal Server Error');
+  util.puts(util.inspect(error));
+};
+
+StaticServlet.prototype.sendMissing_ = function(req, res, path) {
+  path = path.substring(1);
+  res.writeHead(404, {
+      'Content-Type': 'text/html'
+  });
+  res.write('<!doctype html>\n');
+  res.write('<title>404 Not Found</title>\n');
+  res.write('<h1>Not Found</h1>');
+  res.write(
+    '<p>The requested URL ' +
+    escapeHtml(path) +
+    ' was not found on this server.</p>'
+  );
+  res.end();
+  util.puts('404 Not Found: ' + path);
+};
+
+StaticServlet.prototype.sendForbidden_ = function(req, res, path) {
+  path = path.substring(1);
+  res.writeHead(403, {
+      'Content-Type': 'text/html'
+  });
+  res.write('<!doctype html>\n');
+  res.write('<title>403 Forbidden</title>\n');
+  res.write('<h1>Forbidden</h1>');
+  res.write(
+    '<p>You do not have permission to access ' +
+    escapeHtml(path) + ' on this server.</p>'
+  );
+  res.end();
+  util.puts('403 Forbidden: ' + path);
+};
+
+StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) {
+  res.writeHead(301, {
+      'Content-Type': 'text/html',
+      'Location': redirectUrl
+  });
+  res.write('<!doctype html>\n');
+  res.write('<title>301 Moved Permanently</title>\n');
+  res.write('<h1>Moved Permanently</h1>');
+  res.write(
+    '<p>The document has moved <a href="' +
+    redirectUrl +
+    '">here</a>.</p>'
+  );
+  res.end();
+  util.puts('301 Moved Permanently: ' + redirectUrl);
+};
+
+StaticServlet.prototype.sendFile_ = function(req, res, path) {
+  var self = this;
+  var file = fs.createReadStream(path);
+  res.writeHead(200, {
+    'Content-Type': StaticServlet.
+      MimeMap[path.split('.').pop()] || 'text/plain'
+  });
+  if (req.method === 'HEAD') {
+    res.end();
+  } else {
+    file.on('data', res.write.bind(res));
+    file.on('close', function() {
+      res.end();
+    });
+    file.on('error', function(error) {
+      self.sendError_(req, res, error);
+    });
+  }
+};
+
+StaticServlet.prototype.sendDirectory_ = function(req, res, path) {
+  var self = this;
+  if (path.match(/[^\/]$/)) {
+    req.url.pathname += '/';
+    var redirectUrl = url.format(url.parse(url.format(req.url)));
+    return self.sendRedirect_(req, res, redirectUrl);
+  }
+  fs.readdir(path, function(err, files) {
+    if (err)
+      return self.sendError_(req, res, error);
+
+    if (!files.length)
+      return self.writeDirectoryIndex_(req, res, path, []);
+
+    var remaining = files.length;
+    files.forEach(function(fileName, index) {
+      fs.stat(path + '/' + fileName, function(err, stat) {
+        if (err)
+          return self.sendError_(req, res, err);
+        if (stat.isDirectory()) {
+          files[index] = fileName + '/';
+        }
+        if (!(--remaining))
+          return self.writeDirectoryIndex_(req, res, path, files);
+      });
+    });
+  });
+};
+
+StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) {
+  path = path.substring(1);
+  res.writeHead(200, {
+    'Content-Type': 'text/html'
+  });
+  if (req.method === 'HEAD') {
+    res.end();
+    return;
+  }
+  res.write('<!doctype html>\n');
+  res.write('<title>' + escapeHtml(path) + '</title>\n');
+  res.write('<style>\n');
+  res.write('  ol { list-style-type: none; font-size: 1.2em; }\n');
+  res.write('</style>\n');
+  res.write('<h1>Directory: ' + escapeHtml(path) + '</h1>');
+  res.write('<ol>');
+  files.forEach(function(fileName) {
+    if (fileName.charAt(0) !== '.') {
+      res.write('<li><a href="' +
+        escapeHtml(fileName) + '">' +
+        escapeHtml(fileName) + '</a></li>');
+    }
+  });
+  res.write('</ol>');
+  res.end();
+};
+
+// Must be last,
+main(process.argv);
diff --git a/Open-ILS/tests/staffweb/test/unit/egHomeApp.js b/Open-ILS/tests/staffweb/test/unit/egHomeApp.js
new file mode 100644 (file)
index 0000000..31483e6
--- /dev/null
@@ -0,0 +1,25 @@
+'use strict';
+
+describe('egHomeControllers', function(){
+  beforeEach(module('egHome'));
+
+  /* ---- LoginCtrl ---------------------------------- */
+
+  var loginCtrl, loginScope;
+  beforeEach(inject(function ($rootScope, $controller, $location) {
+      // pass the workstation name via (mock) URL param
+      $location.search({ws : 'TestWorkstation'});
+
+      loginScope = $rootScope.$new();
+      loginCtrl = $controller('LoginCtrl', {$scope: loginScope});
+  }));
+
+  it('should focus the login controller', inject(function() {
+    expect(loginScope.focusMe).toBe(true);
+  }));
+
+  it('should set the login workstation', inject(function() {
+    expect(loginScope.args.workstation).toEqual('TestWorkstation');
+  }));
+
+});
diff --git a/Open-ILS/tests/staffweb/test/unit/egPatronApp.js b/Open-ILS/tests/staffweb/test/unit/egPatronApp.js
new file mode 100644 (file)
index 0000000..df9d829
--- /dev/null
@@ -0,0 +1,31 @@
+'use strict';
+
+describe('egPatronAppTest', function(){
+  beforeEach(module('egPatronApp'));
+
+  // basic controller sanity checks
+  
+  var patronCtrl, patronScope;
+  beforeEach(inject(function ($rootScope, $controller, $location) {
+      patronScope = $rootScope.$new();
+      patronCtrl = $controller('PatronCtrl', {$scope: patronScope});
+  }));
+
+  /** patronSvc tests **/
+  describe('patronSvcTests', function() {
+
+    it('patronSvc should start with empty lists', inject(function(patronSvc) {
+        expect(patronSvc.patrons.count()).toEqual(0);
+    }));
+
+    it('patronSvc reset should clear data', inject(function(patronSvc) {
+        patronSvc.checkout_overrides.a = 1;
+        expect(Object.keys(patronSvc.checkout_overrides).length).toBe(1);
+        patronSvc.resetPatronLists();
+        expect(Object.keys(patronSvc.checkout_overrides).length).toBe(0);
+        expect(patronSvc.holds.items.length).toBe(0);
+    }));
+
+  });
+
+});
diff --git a/Open-ILS/tests/staffweb/update-angular.sh b/Open-ILS/tests/staffweb/update-angular.sh
new file mode 100755 (executable)
index 0000000..dd02589
--- /dev/null
@@ -0,0 +1,34 @@
+#! /bin/sh
+
+# --------------------------------------
+# modified added by berick / 2013-12-12
+#  * create needed dirs
+#  * udpate angular-ui-bootstrap code
+
+set -e;
+
+if [ -z "$1" ]; then
+    echo  "$0 <angular-version> <angular-bootstrap-version>"
+    exit;
+fi;
+
+mkdir -p tmp
+mkdir -p app/lib;
+mkdir -p test/lib/angular
+mkdir -p test/lib/angular-ui-bootstrap
+
+curl https://raw.github.com/angular/code.angularjs.org/master/$1/angular-$1.zip -o tmp/angular.zip
+rm -fr app/lib/angular
+unzip tmp/angular.zip -d app/lib
+mv app/lib/angular-$1 app/lib/angular
+rm -fr app/lib/angular/docs
+mv app/lib/angular/angular-mocks.js test/lib/angular
+mv app/lib/angular/angular-scenario.js test/lib/angular
+cp app/lib/angular/version.txt test/lib/angular
+
+if [ -n "$2" ]; then
+  mkdir -p app/lib/angular-ui-bootstrap/
+  curl http://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/$2/ui-bootstrap-tpls.min.js \
+    -o app/lib/angular-ui-bootstrap/angular-bootstrap-min.js
+fi;
+