<commit_before>// Load in dependencies
var fs = require('fs');
var expect = require('chai').expect;
var sinon = require('sinon');
var shell = require('shelljs');
var fixtureUtils = require('./utils/fixtures');
var foundryUtils = require('./utils/foundry');

// TODO: Relocate utils into spec

// Guarantee safeguards against exec are in place (see WARNING.md)
var childUtils = require('./utils/child-process');

// Define our test
describe('A release', function () {
  describe('in a node module (npm)', function () {
    var fixtureDir = fixtureUtils.fixtureDir('npm');
    before(function release (done) {
      // Introduce custom stubbing
      var program = foundryUtils.create({
        allowSetVersion: true
      });

      // When publishing to npm, stub over exec to return all valid calls
      var that = this;
      program.once('publish#before', function () {
        that.execStub = sinon.stub(shell, 'exec');
      });

      // Run through the release
      program.once('publish#after', done);
      program.parse(['node', '/usr/bin/foundry', 'release', '0.1.0']);
    });
    after(function unstub () {
      this.execStub.restore();
    });

    it('updates the package.json', function () {
      var pkgJson = fs.readFileSync(fixtureDir + '/package.json');
      expect(JSON.parse(pkgJson)).to.have.property('version', '0.1.0');
    });
    it('publishes to npm', function () {
      expect(this.execStub.args[0]).to.deep.equal(['npm publish']);
    });
  });

  describe('in a private node module (npm)', function () {
    var fixtureDir = fixtureUtils.fixtureDir('npm-private');
    before(function release (done) {
      // Introduce custom stubbing
      var program = foundryUtils.create({
        allowSetVersion: true
      });

      var that = this;
      program.once('publish#before', function () {
        // TODO: We should be testing against shell.exec on `private: true` for the first call. No stubbing.
        that.execStub = sinon.stub(shell, 'exec', function () {
          return {code: 1};
        });
      });

      // Run through the release
      program.once('publish#after', done);
      program.parse(['node', '/usr/bin/foundry', 'release', '0.1.0']);
    });
    after(function unstub () {
      this.execStub.restore();
    });

    it('updates the package.json', function () {
      var pkgJson = fs.readFileSync(fixtureDir + '/package.json');
      expect(JSON.parse(pkgJson)).to.have.property('version', '0.1.0');
    });
    it('publishes to npm', function () {
      expect(this.execStub.args).to.have.property('length', 0);
    });
  });
});
<commit_msg>Updating test pieces to match new fragmented pattern<commit_after>// Load in dependencies
var fs = require('fs');
var expect = require('chai').expect;
var sinon = require('sinon');
var shell = require('shelljs');
var fixtureUtils = require('./utils/fixtures');
var foundryUtils = require('./utils/foundry');

// TODO: Relocate utils into spec

// Guarantee safeguards against exec are in place (see WARNING.md)
var childUtils = require('./utils/child-process');

// Define our test
describe('Setting the version', function () {
  describe('for a node module', function () {
    var fixtureDir = fixtureUtils.fixtureDir('npm');

    it('updates the package.json', function () {
      var pkgJson = fs.readFileSync(fixtureDir + '/package.json');
      expect(JSON.parse(pkgJson)).to.have.property('version', '0.1.0');
    });

  });
});

describe('Publishing', function () {
  describe('a node module', function () {
    var fixtureDir = fixtureUtils.fixtureDir('npm');
    before(function (done) {
      this.execStub = sinon.stub(shell, 'exec');
    });
    after(function () {
      this.execStub.restore();
    });

    it('publishes to npm', function () {
      expect(this.execStub.args[0]).to.deep.equal(['npm publish']);
    });
  });
  describe('a private node module', function () {
    var fixtureDir = fixtureUtils.fixtureDir('npm-private');
    before(function (done) {
      this.execStub = sinon.stub(shell, 'exec');
    });
    after(function () {
      this.execStub.restore();
    });

    it('publishes to npm', function () {
      expect(this.execStub.args).to.have.property('length', 0);
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

/**
 * Here is the problem: http://bugs.jquery.com/ticket/7292
 * basically jQuery treats change event on some browsers (IE) as a
 * special event and changes it form 'change' to 'click/keydown' and
 * few others. This horrible hack removes the special treatment
 */
if (window._jQuery) _jQuery.event.special.change = undefined;

if (window.bindJQuery) bindJQuery();

beforeEach(function() {
  // all this stuff is not needed for module tests, where jqlite and publishExternalAPI and jqLite are not global vars
  if (window.publishExternalAPI) {
    publishExternalAPI(angular);

    // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
    // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
    // correct this, but only if we are not running in jqLite mode
    if (!_jqLiteMode && _jQuery !== jQuery) {
      jQuery = _jQuery;
    }

    // This resets global id counter;
    uid = ['0', '0', '0'];

    // reset to jQuery or default to us.
    bindJQuery();
  }

  angular.element(document.body).empty().removeData();
});

afterEach(function() {
  if (this.$injector) {
    var $rootScope = this.$injector.get('$rootScope');
    var $rootElement = this.$injector.get('$rootElement');
    var $log = this.$injector.get('$log');
    // release the injector
    dealoc($rootScope);
    dealoc($rootElement);

    // check $log mock
    $log.assertEmpty && $log.assertEmpty();
  }

  // complain about uncleared jqCache references
  var count = 0;

  // This line should be enabled as soon as this bug is fixed: http://bugs.jquery.com/ticket/11775
  //var cache = jqLite.cache;
  var cache = angular.element.cache;

  forEachSorted(cache, function(expando, key){
    angular.forEach(expando.data, function(value, key){
      count ++;
      if (value && value.$element) {
        dump('LEAK', key, value.$id, sortedHtml(value.$element));
      } else {
        dump('LEAK', key, angular.toJson(value));
      }
    });
  });
  if (count) {
    throw new Error('Found jqCache references that were not deallocated! count: ' + count);
  }

  // copied from Angular.js
  // we need these two methods here so that we can run module tests with wrapped angular.js
  function sortedKeys(obj) {
    var keys = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keys.push(key);
      }
    }
    return keys.sort();
  }

  function forEachSorted(obj, iterator, context) {
    var keys = sortedKeys(obj);
    for ( var i = 0; i < keys.length; i++) {
      iterator.call(context, obj[keys[i]], keys[i]);
    }
    return keys;
  }
});

function dealoc(obj) {
  var jqCache = angular.element.cache;
  if (obj) {
    if (angular.isElement(obj)) {
      cleanup(angular.element(obj));
    } else {
      for(var key in jqCache) {
        var value = jqCache[key];
        if (value.data && value.data.$scope == obj) {
          delete jqCache[key];
        }
      }
    }
  }

  function cleanup(element) {
    element.off().removeData();
    // Note:  We aren't using element.contents() here.  Under jQuery, element.contents() can fail
    // for IFRAME elements.  jQuery explicitly uses (element.contentDocument ||
    // element.contentWindow.document) and both properties are null for IFRAMES that aren't attached
    // to a document.
    var children = element[0].childNodes || [];
    for ( var i = 0; i < children.length; i++) {
      cleanup(angular.element(children[i]));
    }
  }
}

/**
 * @param {DOMElement} element
 * @param {boolean=} showNgClass
 */
function sortedHtml(element, showNgClass) {
  var html = "";
  forEach(jqLite(element), function toString(node) {

    if (node.nodeName == "#text") {
      html += node.nodeValue.
        replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
        replace(/</g, '<').
        replace(/>/g, '>');
    } else if (node.nodeName == "#comment") {
      html += '<!--' + node.nodeValue + '-->';
    } else {
      html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
      var attributes = node.attributes || [];
      var attrs = [];
      var className = node.className || '';
      if (!showNgClass) {
        className = className.replace(/ng-[\w-]+\s*/g, '');
      }
      className = trim(className);
      if (className) {
        attrs.push(' class="' + className + '"');
      }
      for(var i=0; i<attributes.length; i++) {
        if (i>0 && attributes[i] == attributes[i-1])
          continue; //IE9 creates dupes. Ignore them!

        var attr = attributes[i];
        if(attr.name.match(/^ng[\:\-]/) ||
            (attr.value || attr.value == '') &&
            attr.value !='null' &&
            attr.value !='auto' &&
            attr.value !='false' &&
            attr.value !='inherit' &&
            (attr.value !='0' || attr.name =='value') &&
            attr.name !='loop' &&
            attr.name !='complete' &&
            attr.name !='maxLength' &&
            attr.name !='size' &&
            attr.name !='class' &&
            attr.name !='start' &&
            attr.name !='tabIndex' &&
            attr.name !='style' &&
            attr.name.substr(0, 6) != 'jQuery') {
          // in IE we need to check for all of these.
          if (/ng-\d+/.exec(attr.name) ||
              attr.name == 'getElementById' ||
              // IE7 has `selected` in attributes
              attr.name == 'selected' ||
              // IE7 adds `value` attribute to all LI tags
              (node.nodeName == 'LI' && attr.name == 'value') ||
              // IE8 adds bogus rowspan=1 and colspan=1 to TD elements
              (node.nodeName == 'TD' && attr.name == 'rowSpan' && attr.value == '1') ||
              (node.nodeName == 'TD' && attr.name == 'colSpan' && attr.value == '1')) {
            continue;
          }

          attrs.push(' ' + attr.name + '="' + attr.value + '"');
        }
      }
      attrs.sort();
      html += attrs.join('');
      if (node.style) {
        var style = [];
        if (node.style.cssText) {
          forEach(node.style.cssText.split(';'), function(value){
            value = trim(value);
            if (value) {
              style.push(lowercase(value));
            }
          });
        }
        for(var css in node.style){
          var value = node.style[css];
          if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
            var text = lowercase(css + ': ' + value);
            if (value != 'false' && indexOf(style, text) == -1) {
              style.push(text);
            }
          }
        }
        style.sort();
        var tmp = style;
        style = [];
        forEach(tmp, function(value){
          if (!value.match(/^max[^\-]/))
            style.push(value);
        });
        if (style.length) {
          html += ' style="' + style.join('; ') + ';"';
        }
      }
      html += '>';
      var children = node.childNodes;
      for(var j=0; j<children.length; j++) {
        toString(children[j]);
      }
      html += '</' + node.nodeName.toLowerCase() + '>';
    }
  });
  return html;
}

function childrenTagsOf(element) {
  var tags = [];

  forEach(jqLite(element).children(), function(child) {
    tags.push(child.nodeName.toLowerCase());
  });

  return tags;
}

// TODO(vojta): migrate these helpers into jasmine matchers
/**a
 * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
 * actually test if an element is displayed by the browser. Be aware!!!
 */
function isCssVisible(node) {
  var display = node.css('display');
  return !node.hasClass('ng-hide') && display != 'none';
}

function assertHidden(node) {
  if (isCssVisible(node)) {
    throw new Error('Node should be hidden but was visible: ' + angular.module.ngMock.dump(node));
  }
}

function assertVisible(node) {
  if (!isCssVisible(node)) {
    throw new Error('Node should be visible but was hidden: ' + angular.module.ngMock.dump(node));
  }
}

function provideLog($provide) {
  $provide.factory('log', function() {
      var messages = [];

      function log(msg) {
        messages.push(msg);
        return msg;
      }

      log.toString = function() {
        return messages.join('; ');
      }

      log.toArray = function() {
        return messages;
      }

      log.reset = function() {
        messages = [];
      }

      log.fn = function(msg) {
        return function() {
          log(msg);
        }
      }

      log.$$log = true;

      return log;
    });
}

function pending() {
  dump('PENDING');
};

function trace(name) {
  dump(new Error(name).stack);
}

var karmaDump = dump;
window.dump = function () {
  karmaDump.apply(undefined, map(arguments, function(arg) {
    return angular.mock.dump(arg);
  }));
};
<commit_msg>chore(log): add `log.empty()`  method to the testing logger<commit_after>'use strict';

/**
 * Here is the problem: http://bugs.jquery.com/ticket/7292
 * basically jQuery treats change event on some browsers (IE) as a
 * special event and changes it form 'change' to 'click/keydown' and
 * few others. This horrible hack removes the special treatment
 */
if (window._jQuery) _jQuery.event.special.change = undefined;

if (window.bindJQuery) bindJQuery();

beforeEach(function() {
  // all this stuff is not needed for module tests, where jqlite and publishExternalAPI and jqLite are not global vars
  if (window.publishExternalAPI) {
    publishExternalAPI(angular);

    // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
    // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
    // correct this, but only if we are not running in jqLite mode
    if (!_jqLiteMode && _jQuery !== jQuery) {
      jQuery = _jQuery;
    }

    // This resets global id counter;
    uid = ['0', '0', '0'];

    // reset to jQuery or default to us.
    bindJQuery();
  }

  angular.element(document.body).empty().removeData();
});

afterEach(function() {
  if (this.$injector) {
    var $rootScope = this.$injector.get('$rootScope');
    var $rootElement = this.$injector.get('$rootElement');
    var $log = this.$injector.get('$log');
    // release the injector
    dealoc($rootScope);
    dealoc($rootElement);

    // check $log mock
    $log.assertEmpty && $log.assertEmpty();
  }

  // complain about uncleared jqCache references
  var count = 0;

  // This line should be enabled as soon as this bug is fixed: http://bugs.jquery.com/ticket/11775
  //var cache = jqLite.cache;
  var cache = angular.element.cache;

  forEachSorted(cache, function(expando, key){
    angular.forEach(expando.data, function(value, key){
      count ++;
      if (value && value.$element) {
        dump('LEAK', key, value.$id, sortedHtml(value.$element));
      } else {
        dump('LEAK', key, angular.toJson(value));
      }
    });
  });
  if (count) {
    throw new Error('Found jqCache references that were not deallocated! count: ' + count);
  }

  // copied from Angular.js
  // we need these two methods here so that we can run module tests with wrapped angular.js
  function sortedKeys(obj) {
    var keys = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keys.push(key);
      }
    }
    return keys.sort();
  }

  function forEachSorted(obj, iterator, context) {
    var keys = sortedKeys(obj);
    for ( var i = 0; i < keys.length; i++) {
      iterator.call(context, obj[keys[i]], keys[i]);
    }
    return keys;
  }
});

function dealoc(obj) {
  var jqCache = angular.element.cache;
  if (obj) {
    if (angular.isElement(obj)) {
      cleanup(angular.element(obj));
    } else {
      for(var key in jqCache) {
        var value = jqCache[key];
        if (value.data && value.data.$scope == obj) {
          delete jqCache[key];
        }
      }
    }
  }

  function cleanup(element) {
    element.off().removeData();
    // Note:  We aren't using element.contents() here.  Under jQuery, element.contents() can fail
    // for IFRAME elements.  jQuery explicitly uses (element.contentDocument ||
    // element.contentWindow.document) and both properties are null for IFRAMES that aren't attached
    // to a document.
    var children = element[0].childNodes || [];
    for ( var i = 0; i < children.length; i++) {
      cleanup(angular.element(children[i]));
    }
  }
}

/**
 * @param {DOMElement} element
 * @param {boolean=} showNgClass
 */
function sortedHtml(element, showNgClass) {
  var html = "";
  forEach(jqLite(element), function toString(node) {

    if (node.nodeName == "#text") {
      html += node.nodeValue.
        replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
        replace(/</g, '<').
        replace(/>/g, '>');
    } else if (node.nodeName == "#comment") {
      html += '<!--' + node.nodeValue + '-->';
    } else {
      html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
      var attributes = node.attributes || [];
      var attrs = [];
      var className = node.className || '';
      if (!showNgClass) {
        className = className.replace(/ng-[\w-]+\s*/g, '');
      }
      className = trim(className);
      if (className) {
        attrs.push(' class="' + className + '"');
      }
      for(var i=0; i<attributes.length; i++) {
        if (i>0 && attributes[i] == attributes[i-1])
          continue; //IE9 creates dupes. Ignore them!

        var attr = attributes[i];
        if(attr.name.match(/^ng[\:\-]/) ||
            (attr.value || attr.value == '') &&
            attr.value !='null' &&
            attr.value !='auto' &&
            attr.value !='false' &&
            attr.value !='inherit' &&
            (attr.value !='0' || attr.name =='value') &&
            attr.name !='loop' &&
            attr.name !='complete' &&
            attr.name !='maxLength' &&
            attr.name !='size' &&
            attr.name !='class' &&
            attr.name !='start' &&
            attr.name !='tabIndex' &&
            attr.name !='style' &&
            attr.name.substr(0, 6) != 'jQuery') {
          // in IE we need to check for all of these.
          if (/ng-\d+/.exec(attr.name) ||
              attr.name == 'getElementById' ||
              // IE7 has `selected` in attributes
              attr.name == 'selected' ||
              // IE7 adds `value` attribute to all LI tags
              (node.nodeName == 'LI' && attr.name == 'value') ||
              // IE8 adds bogus rowspan=1 and colspan=1 to TD elements
              (node.nodeName == 'TD' && attr.name == 'rowSpan' && attr.value == '1') ||
              (node.nodeName == 'TD' && attr.name == 'colSpan' && attr.value == '1')) {
            continue;
          }

          attrs.push(' ' + attr.name + '="' + attr.value + '"');
        }
      }
      attrs.sort();
      html += attrs.join('');
      if (node.style) {
        var style = [];
        if (node.style.cssText) {
          forEach(node.style.cssText.split(';'), function(value){
            value = trim(value);
            if (value) {
              style.push(lowercase(value));
            }
          });
        }
        for(var css in node.style){
          var value = node.style[css];
          if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
            var text = lowercase(css + ': ' + value);
            if (value != 'false' && indexOf(style, text) == -1) {
              style.push(text);
            }
          }
        }
        style.sort();
        var tmp = style;
        style = [];
        forEach(tmp, function(value){
          if (!value.match(/^max[^\-]/))
            style.push(value);
        });
        if (style.length) {
          html += ' style="' + style.join('; ') + ';"';
        }
      }
      html += '>';
      var children = node.childNodes;
      for(var j=0; j<children.length; j++) {
        toString(children[j]);
      }
      html += '</' + node.nodeName.toLowerCase() + '>';
    }
  });
  return html;
}

function childrenTagsOf(element) {
  var tags = [];

  forEach(jqLite(element).children(), function(child) {
    tags.push(child.nodeName.toLowerCase());
  });

  return tags;
}

// TODO(vojta): migrate these helpers into jasmine matchers
/**a
 * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
 * actually test if an element is displayed by the browser. Be aware!!!
 */
function isCssVisible(node) {
  var display = node.css('display');
  return !node.hasClass('ng-hide') && display != 'none';
}

function assertHidden(node) {
  if (isCssVisible(node)) {
    throw new Error('Node should be hidden but was visible: ' + angular.module.ngMock.dump(node));
  }
}

function assertVisible(node) {
  if (!isCssVisible(node)) {
    throw new Error('Node should be visible but was hidden: ' + angular.module.ngMock.dump(node));
  }
}

function provideLog($provide) {
  $provide.factory('log', function() {
      var messages = [];

      function log(msg) {
        messages.push(msg);
        return msg;
      }

      log.toString = function() {
        return messages.join('; ');
      };

      log.toArray = function() {
        return messages;
      };

      log.reset = function() {
        messages = [];
      };

      log.empty = function() {
        var currentMessages = messages;
        messages = [];
        return currentMessages;
      }

      log.fn = function(msg) {
        return function() {
          log(msg);
        };
      };

      log.$$log = true;

      return log;
    });
}

function pending() {
  dump('PENDING');
};

function trace(name) {
  dump(new Error(name).stack);
}

var karmaDump = dump;
window.dump = function () {
  karmaDump.apply(undefined, map(arguments, function(arg) {
    return angular.mock.dump(arg);
  }));
};
<|endoftext|>


<commit_before>/* global jQuery: true, uid: true */
'use strict';

/**
 * Here is the problem: http://bugs.jquery.com/ticket/7292
 * basically jQuery treats change event on some browsers (IE) as a
 * special event and changes it form 'change' to 'click/keydown' and
 * few others. This horrible hack removes the special treatment
 */
if (window._jQuery) _jQuery.event.special.change = undefined;

if (window.bindJQuery) bindJQuery();

beforeEach(function() {
  // all this stuff is not needed for module tests, where jqlite and publishExternalAPI and jqLite are not global vars
  if (window.publishExternalAPI) {
    publishExternalAPI(angular);

    // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
    // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
    // correct this, but only if we are not running in jqLite mode
    if (!_jqLiteMode && _jQuery !== jQuery) {
      jQuery = _jQuery;
    }

    // This resets global id counter;
    uid = 0;

    // reset to jQuery or default to us.
    bindJQuery();
    jqLiteCacheSizeInit();
  }

  angular.element(document.body).empty().removeData();
});

afterEach(function() {
  var count, cache;

  if (this.$injector) {
    var $rootScope = this.$injector.get('$rootScope');
    var $rootElement = this.$injector.get('$rootElement');
    var $log = this.$injector.get('$log');
    // release the injector
    dealoc($rootScope);
    dealoc($rootElement);

    // check $log mock
    $log.assertEmpty && $log.assertEmpty();
  }

  if (!window.jQuery) {
    // jQuery 2.x doesn't expose the cache storage.

    // complain about uncleared jqCache references
    count = 0;

    cache = angular.element.cache;

    forEachSorted(cache, function (expando, key) {
      angular.forEach(expando.data, function (value, key) {
        count++;
        if (value && value.$element) {
          dump('LEAK', key, value.$id, sortedHtml(value.$element));
        } else {
          dump('LEAK', key, angular.toJson(value));
        }
      });
    });
    if (count) {
      throw new Error('Found jqCache references that were not deallocated! count: ' + count);
    }
  }

  // copied from Angular.js
  // we need these two methods here so that we can run module tests with wrapped angular.js
  function sortedKeys(obj) {
    var keys = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keys.push(key);
      }
    }
    return keys.sort();
  }

  function forEachSorted(obj, iterator, context) {
    var keys = sortedKeys(obj);
    for ( var i = 0; i < keys.length; i++) {
      iterator.call(context, obj[keys[i]], keys[i]);
    }
    return keys;
  }
});

function dealoc(obj) {
  var jqCache = angular.element.cache;
  if (obj) {
    if (angular.isElement(obj)) {
      cleanup(angular.element(obj));
    } else if (!window.jQuery) {
      // jQuery 2.x doesn't expose the cache storage.
      for (var key in jqCache) {
        var value = jqCache[key];
        if (value.data && value.data.$scope == obj) {
          delete jqCache[key];
        }
      }
    }
  }

  function cleanup(element) {
    element.off().removeData();
    if (window.jQuery) {
      // jQuery 2.x doesn't expose the cache storage; ensure all element data
      // is removed during its cleanup.
      jQuery.cleanData([element]);
    }
    // Note:  We aren't using element.contents() here.  Under jQuery, element.contents() can fail
    // for IFRAME elements.  jQuery explicitly uses (element.contentDocument ||
    // element.contentWindow.document) and both properties are null for IFRAMES that aren't attached
    // to a document.
    var children = element[0].childNodes || [];
    for ( var i = 0; i < children.length; i++) {
      cleanup(angular.element(children[i]));
    }
  }
}

function jqLiteCacheSize() {
  var size = 0;
  forEach(jqLite.cache, function() { size++; });
  return size - jqLiteCacheSize.initSize;
}
jqLiteCacheSize.initSize = 0;

function jqLiteCacheSizeInit() {
  jqLiteCacheSize.initSize = jqLiteCacheSize.initSize + jqLiteCacheSize();
}

/**
 * @param {DOMElement} element
 * @param {boolean=} showNgClass
 */
function sortedHtml(element, showNgClass) {
  var html = "";
  forEach(jqLite(element), function toString(node) {

    if (node.nodeName == "#text") {
      html += node.nodeValue.
        replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
        replace(/</g, '<').
        replace(/>/g, '>');
    } else if (node.nodeName == "#comment") {
      html += '<!--' + node.nodeValue + '-->';
    } else {
      html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
      var attributes = node.attributes || [];
      var attrs = [];
      var className = node.className || '';
      if (!showNgClass) {
        className = className.replace(/ng-[\w-]+\s*/g, '');
      }
      className = trim(className);
      if (className) {
        attrs.push(' class="' + className + '"');
      }
      for(var i=0; i<attributes.length; i++) {
        if (i>0 && attributes[i] == attributes[i-1])
          continue; //IE9 creates dupes. Ignore them!

        var attr = attributes[i];
        if(attr.name.match(/^ng[\:\-]/) ||
            (attr.value || attr.value === '') &&
            attr.value !='null' &&
            attr.value !='auto' &&
            attr.value !='false' &&
            attr.value !='inherit' &&
            (attr.value !='0' || attr.name =='value') &&
            attr.name !='loop' &&
            attr.name !='complete' &&
            attr.name !='maxLength' &&
            attr.name !='size' &&
            attr.name !='class' &&
            attr.name !='start' &&
            attr.name !='tabIndex' &&
            attr.name !='style' &&
            attr.name.substr(0, 6) != 'jQuery') {
          // in IE we need to check for all of these.
          if (/ng\d+/.exec(attr.name) ||
              attr.name == 'getElementById' ||
              // IE7 has `selected` in attributes
              attr.name == 'selected' ||
              // IE7 adds `value` attribute to all LI tags
              (node.nodeName == 'LI' && attr.name == 'value') ||
              // IE8 adds bogus rowspan=1 and colspan=1 to TD elements
              (node.nodeName == 'TD' && attr.name == 'rowSpan' && attr.value == '1') ||
              (node.nodeName == 'TD' && attr.name == 'colSpan' && attr.value == '1')) {
            continue;
          }

          attrs.push(' ' + attr.name + '="' + attr.value + '"');
        }
      }
      attrs.sort();
      html += attrs.join('');
      if (node.style) {
        var style = [];
        if (node.style.cssText) {
          forEach(node.style.cssText.split(';'), function(value){
            value = trim(value);
            if (value) {
              style.push(lowercase(value));
            }
          });
        }
        for(var css in node.style){
          var value = node.style[css];
          if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
            var text = lowercase(css + ': ' + value);
            if (value != 'false' && style.indexOf(text) == -1) {
              style.push(text);
            }
          }
        }
        style.sort();
        var tmp = style;
        style = [];
        forEach(tmp, function(value){
          if (!value.match(/^max[^\-]/))
            style.push(value);
        });
        if (style.length) {
          html += ' style="' + style.join('; ') + ';"';
        }
      }
      html += '>';
      var children = node.childNodes;
      for(var j=0; j<children.length; j++) {
        toString(children[j]);
      }
      html += '</' + node.nodeName.toLowerCase() + '>';
    }
  });
  return html;
}

function childrenTagsOf(element) {
  var tags = [];

  forEach(jqLite(element).children(), function(child) {
    tags.push(child.nodeName.toLowerCase());
  });

  return tags;
}

// TODO(vojta): migrate these helpers into jasmine matchers
/**a
 * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
 * actually test if an element is displayed by the browser. Be aware!!!
 */
function isCssVisible(node) {
  var display = node.css('display');
  return !node.hasClass('ng-hide') && display != 'none';
}

function assertHidden(node) {
  if (isCssVisible(node)) {
    throw new Error('Node should be hidden but was visible: ' + angular.mock.dump(node));
  }
}

function assertVisible(node) {
  if (!isCssVisible(node)) {
    throw new Error('Node should be visible but was hidden: ' + angular.mock.dump(node));
  }
}

function provideLog($provide) {
  $provide.factory('log', function() {
      var messages = [];

      function log(msg) {
        messages.push(msg);
        return msg;
      }

      log.toString = function() {
        return messages.join('; ');
      };

      log.toArray = function() {
        return messages;
      };

      log.reset = function() {
        messages = [];
      };

      log.empty = function() {
        var currentMessages = messages;
        messages = [];
        return currentMessages;
      };

      log.fn = function(msg) {
        return function() {
          log(msg);
        };
      };

      log.$$log = true;

      return log;
    });
}

function pending() {
  dump('PENDING');
}

function trace(name) {
  dump(new Error(name).stack);
}

var karmaDump = dump;
window.dump = function () {
  karmaDump.apply(undefined, map(arguments, function(arg) {
    return angular.mock.dump(arg);
  }));
};
<commit_msg>chore(testabilityPatch): fix the dump fn so that it works with karma's debug.html<commit_after>/* global jQuery: true, uid: true */
'use strict';

/**
 * Here is the problem: http://bugs.jquery.com/ticket/7292
 * basically jQuery treats change event on some browsers (IE) as a
 * special event and changes it form 'change' to 'click/keydown' and
 * few others. This horrible hack removes the special treatment
 */
if (window._jQuery) _jQuery.event.special.change = undefined;

if (window.bindJQuery) bindJQuery();

beforeEach(function() {
  // all this stuff is not needed for module tests, where jqlite and publishExternalAPI and jqLite are not global vars
  if (window.publishExternalAPI) {
    publishExternalAPI(angular);

    // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
    // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
    // correct this, but only if we are not running in jqLite mode
    if (!_jqLiteMode && _jQuery !== jQuery) {
      jQuery = _jQuery;
    }

    // This resets global id counter;
    uid = 0;

    // reset to jQuery or default to us.
    bindJQuery();
    jqLiteCacheSizeInit();
  }

  angular.element(document.body).empty().removeData();
});

afterEach(function() {
  var count, cache;

  if (this.$injector) {
    var $rootScope = this.$injector.get('$rootScope');
    var $rootElement = this.$injector.get('$rootElement');
    var $log = this.$injector.get('$log');
    // release the injector
    dealoc($rootScope);
    dealoc($rootElement);

    // check $log mock
    $log.assertEmpty && $log.assertEmpty();
  }

  if (!window.jQuery) {
    // jQuery 2.x doesn't expose the cache storage.

    // complain about uncleared jqCache references
    count = 0;

    cache = angular.element.cache;

    forEachSorted(cache, function (expando, key) {
      angular.forEach(expando.data, function (value, key) {
        count++;
        if (value && value.$element) {
          dump('LEAK', key, value.$id, sortedHtml(value.$element));
        } else {
          dump('LEAK', key, angular.toJson(value));
        }
      });
    });
    if (count) {
      throw new Error('Found jqCache references that were not deallocated! count: ' + count);
    }
  }

  // copied from Angular.js
  // we need these two methods here so that we can run module tests with wrapped angular.js
  function sortedKeys(obj) {
    var keys = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keys.push(key);
      }
    }
    return keys.sort();
  }

  function forEachSorted(obj, iterator, context) {
    var keys = sortedKeys(obj);
    for ( var i = 0; i < keys.length; i++) {
      iterator.call(context, obj[keys[i]], keys[i]);
    }
    return keys;
  }
});

function dealoc(obj) {
  var jqCache = angular.element.cache;
  if (obj) {
    if (angular.isElement(obj)) {
      cleanup(angular.element(obj));
    } else if (!window.jQuery) {
      // jQuery 2.x doesn't expose the cache storage.
      for (var key in jqCache) {
        var value = jqCache[key];
        if (value.data && value.data.$scope == obj) {
          delete jqCache[key];
        }
      }
    }
  }

  function cleanup(element) {
    element.off().removeData();
    if (window.jQuery) {
      // jQuery 2.x doesn't expose the cache storage; ensure all element data
      // is removed during its cleanup.
      jQuery.cleanData([element]);
    }
    // Note:  We aren't using element.contents() here.  Under jQuery, element.contents() can fail
    // for IFRAME elements.  jQuery explicitly uses (element.contentDocument ||
    // element.contentWindow.document) and both properties are null for IFRAMES that aren't attached
    // to a document.
    var children = element[0].childNodes || [];
    for ( var i = 0; i < children.length; i++) {
      cleanup(angular.element(children[i]));
    }
  }
}

function jqLiteCacheSize() {
  var size = 0;
  forEach(jqLite.cache, function() { size++; });
  return size - jqLiteCacheSize.initSize;
}
jqLiteCacheSize.initSize = 0;

function jqLiteCacheSizeInit() {
  jqLiteCacheSize.initSize = jqLiteCacheSize.initSize + jqLiteCacheSize();
}

/**
 * @param {DOMElement} element
 * @param {boolean=} showNgClass
 */
function sortedHtml(element, showNgClass) {
  var html = "";
  forEach(jqLite(element), function toString(node) {

    if (node.nodeName == "#text") {
      html += node.nodeValue.
        replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
        replace(/</g, '<').
        replace(/>/g, '>');
    } else if (node.nodeName == "#comment") {
      html += '<!--' + node.nodeValue + '-->';
    } else {
      html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
      var attributes = node.attributes || [];
      var attrs = [];
      var className = node.className || '';
      if (!showNgClass) {
        className = className.replace(/ng-[\w-]+\s*/g, '');
      }
      className = trim(className);
      if (className) {
        attrs.push(' class="' + className + '"');
      }
      for(var i=0; i<attributes.length; i++) {
        if (i>0 && attributes[i] == attributes[i-1])
          continue; //IE9 creates dupes. Ignore them!

        var attr = attributes[i];
        if(attr.name.match(/^ng[\:\-]/) ||
            (attr.value || attr.value === '') &&
            attr.value !='null' &&
            attr.value !='auto' &&
            attr.value !='false' &&
            attr.value !='inherit' &&
            (attr.value !='0' || attr.name =='value') &&
            attr.name !='loop' &&
            attr.name !='complete' &&
            attr.name !='maxLength' &&
            attr.name !='size' &&
            attr.name !='class' &&
            attr.name !='start' &&
            attr.name !='tabIndex' &&
            attr.name !='style' &&
            attr.name.substr(0, 6) != 'jQuery') {
          // in IE we need to check for all of these.
          if (/ng\d+/.exec(attr.name) ||
              attr.name == 'getElementById' ||
              // IE7 has `selected` in attributes
              attr.name == 'selected' ||
              // IE7 adds `value` attribute to all LI tags
              (node.nodeName == 'LI' && attr.name == 'value') ||
              // IE8 adds bogus rowspan=1 and colspan=1 to TD elements
              (node.nodeName == 'TD' && attr.name == 'rowSpan' && attr.value == '1') ||
              (node.nodeName == 'TD' && attr.name == 'colSpan' && attr.value == '1')) {
            continue;
          }

          attrs.push(' ' + attr.name + '="' + attr.value + '"');
        }
      }
      attrs.sort();
      html += attrs.join('');
      if (node.style) {
        var style = [];
        if (node.style.cssText) {
          forEach(node.style.cssText.split(';'), function(value){
            value = trim(value);
            if (value) {
              style.push(lowercase(value));
            }
          });
        }
        for(var css in node.style){
          var value = node.style[css];
          if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
            var text = lowercase(css + ': ' + value);
            if (value != 'false' && style.indexOf(text) == -1) {
              style.push(text);
            }
          }
        }
        style.sort();
        var tmp = style;
        style = [];
        forEach(tmp, function(value){
          if (!value.match(/^max[^\-]/))
            style.push(value);
        });
        if (style.length) {
          html += ' style="' + style.join('; ') + ';"';
        }
      }
      html += '>';
      var children = node.childNodes;
      for(var j=0; j<children.length; j++) {
        toString(children[j]);
      }
      html += '</' + node.nodeName.toLowerCase() + '>';
    }
  });
  return html;
}

function childrenTagsOf(element) {
  var tags = [];

  forEach(jqLite(element).children(), function(child) {
    tags.push(child.nodeName.toLowerCase());
  });

  return tags;
}

// TODO(vojta): migrate these helpers into jasmine matchers
/**a
 * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
 * actually test if an element is displayed by the browser. Be aware!!!
 */
function isCssVisible(node) {
  var display = node.css('display');
  return !node.hasClass('ng-hide') && display != 'none';
}

function assertHidden(node) {
  if (isCssVisible(node)) {
    throw new Error('Node should be hidden but was visible: ' + angular.mock.dump(node));
  }
}

function assertVisible(node) {
  if (!isCssVisible(node)) {
    throw new Error('Node should be visible but was hidden: ' + angular.mock.dump(node));
  }
}

function provideLog($provide) {
  $provide.factory('log', function() {
      var messages = [];

      function log(msg) {
        messages.push(msg);
        return msg;
      }

      log.toString = function() {
        return messages.join('; ');
      };

      log.toArray = function() {
        return messages;
      };

      log.reset = function() {
        messages = [];
      };

      log.empty = function() {
        var currentMessages = messages;
        messages = [];
        return currentMessages;
      };

      log.fn = function(msg) {
        return function() {
          log(msg);
        };
      };

      log.$$log = true;

      return log;
    });
}

function pending() {
  window.dump('PENDING');
}

function trace(name) {
  window.dump(new Error(name).stack);
}

var karmaDump = window.dump || function() {
  window.console.log.apply(window.console, arguments);
};

window.dump = function () {
  karmaDump.apply(undefined, map(arguments, function(arg) {
    return angular.mock.dump(arg);
  }));
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Here is the problem: http://bugs.jquery.com/ticket/7292
 * basically jQuery treats change event on some browsers (IE) as a
 * special event and changes it form 'change' to 'click/keydown' and
 * few others. This horrible hack removes the special treatment
 */
if (window._jQuery) _jQuery.event.special.change = undefined;

if (window.bindJQuery) bindJQuery();

beforeEach(function() {
  // all this stuff is not needed for module tests, where jqlite and publishExternalAPI and jqLite are not global vars
  if (window.publishExternalAPI) {
    publishExternalAPI(angular);

    // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
    // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
    // correct this, but only if we are not running in jqLite mode
    if (!_jqLiteMode && _jQuery !== jQuery) {
      jQuery = _jQuery;
    }

    // This resets global id counter;
    uid = ['0', '0', '0'];

    // reset to jQuery or default to us.
    bindJQuery();
  }

  angular.element(document.body).empty().removeData();
});

afterEach(function() {
  if (this.$injector) {
    var $rootScope = this.$injector.get('$rootScope');
    var $rootElement = this.$injector.get('$rootElement');
    var $log = this.$injector.get('$log');
    // release the injector
    dealoc($rootScope);
    dealoc($rootElement);

    // check $log mock
    $log.assertEmpty && $log.assertEmpty();
  }

  // complain about uncleared jqCache references
  var count = 0;

  // This line should be enabled as soon as this bug is fixed: http://bugs.jquery.com/ticket/11775
  //var cache = jqLite.cache;
  var cache = angular.element.cache;

  forEachSorted(cache, function(expando, key){
    angular.forEach(expando.data, function(value, key){
      count ++;
      if (value && value.$element) {
        dump('LEAK', key, value.$id, sortedHtml(value.$element));
      } else {
        dump('LEAK', key, angular.toJson(value));
      }
    });
  });
  if (count) {
    throw new Error('Found jqCache references that were not deallocated! count: ' + count);
  }

  // copied from Angular.js
  // we need these two methods here so that we can run module tests with wrapped angular.js
  function sortedKeys(obj) {
    var keys = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keys.push(key);
      }
    }
    return keys.sort();
  }

  function forEachSorted(obj, iterator, context) {
    var keys = sortedKeys(obj);
    for ( var i = 0; i < keys.length; i++) {
      iterator.call(context, obj[keys[i]], keys[i]);
    }
    return keys;
  }
});

function dealoc(obj) {
  var jqCache = angular.element.cache;
  if (obj) {
    if (angular.isElement(obj)) {
      cleanup(angular.element(obj));
    } else {
      for(var key in jqCache) {
        var value = jqCache[key];
        if (value.data && value.data.$scope == obj) {
          delete jqCache[key];
        }
      }
    }
  }

  function cleanup(element) {
    element.off().removeData();
    // Note:  We aren't using element.contents() here.  Under jQuery, element.contents() can fail
    // for IFRAME elements.  jQuery explicitly uses (element.contentDocument ||
    // element.contentWindow.document) and both properties are null for IFRAMES that aren't attached
    // to a document.
    var children = element[0].childNodes || [];
    for ( var i = 0; i < children.length; i++) {
      cleanup(angular.element(children[i]));
    }
  }
}

/**
 * @param {DOMElement} element
 * @param {boolean=} showNgClass
 */
function sortedHtml(element, showNgClass) {
  var html = "";
  forEach(jqLite(element), function toString(node) {

    if (node.nodeName == "#text") {
      html += node.nodeValue.
        replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
        replace(/</g, '<').
        replace(/>/g, '>');
    } else if (node.nodeName == "#comment") {
      html += '<!--' + node.nodeValue + '-->';
    } else {
      html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
      var attributes = node.attributes || [];
      var attrs = [];
      var className = node.className || '';
      if (!showNgClass) {
        className = className.replace(/ng-[\w-]+\s*/g, '');
      }
      className = trim(className);
      if (className) {
        attrs.push(' class="' + className + '"');
      }
      for(var i=0; i<attributes.length; i++) {
        if (i>0 && attributes[i] == attributes[i-1])
          continue; //IE9 creates dupes. Ignore them!

        var attr = attributes[i];
        if(attr.name.match(/^ng[\:\-]/) ||
            (attr.value || attr.value == '') &&
            attr.value !='null' &&
            attr.value !='auto' &&
            attr.value !='false' &&
            attr.value !='inherit' &&
            (attr.value !='0' || attr.name =='value') &&
            attr.name !='loop' &&
            attr.name !='complete' &&
            attr.name !='maxLength' &&
            attr.name !='size' &&
            attr.name !='class' &&
            attr.name !='start' &&
            attr.name !='tabIndex' &&
            attr.name !='style' &&
            attr.name.substr(0, 6) != 'jQuery') {
          // in IE we need to check for all of these.
          if (/ng\d+/.exec(attr.name) ||
              attr.name == 'getElementById' ||
              // IE7 has `selected` in attributes
              attr.name == 'selected' ||
              // IE7 adds `value` attribute to all LI tags
              (node.nodeName == 'LI' && attr.name == 'value') ||
              // IE8 adds bogus rowspan=1 and colspan=1 to TD elements
              (node.nodeName == 'TD' && attr.name == 'rowSpan' && attr.value == '1') ||
              (node.nodeName == 'TD' && attr.name == 'colSpan' && attr.value == '1')) {
            continue;
          }

          attrs.push(' ' + attr.name + '="' + attr.value + '"');
        }
      }
      attrs.sort();
      html += attrs.join('');
      if (node.style) {
        var style = [];
        if (node.style.cssText) {
          forEach(node.style.cssText.split(';'), function(value){
            value = trim(value);
            if (value) {
              style.push(lowercase(value));
            }
          });
        }
        for(var css in node.style){
          var value = node.style[css];
          if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
            var text = lowercase(css + ': ' + value);
            if (value != 'false' && indexOf(style, text) == -1) {
              style.push(text);
            }
          }
        }
        style.sort();
        var tmp = style;
        style = [];
        forEach(tmp, function(value){
          if (!value.match(/^max[^\-]/))
            style.push(value);
        });
        if (style.length) {
          html += ' style="' + style.join('; ') + ';"';
        }
      }
      html += '>';
      var children = node.childNodes;
      for(var j=0; j<children.length; j++) {
        toString(children[j]);
      }
      html += '</' + node.nodeName.toLowerCase() + '>';
    }
  });
  return html;
}

function childrenTagsOf(element) {
  var tags = [];

  forEach(jqLite(element).children(), function(child) {
    tags.push(child.nodeName.toLowerCase());
  });

  return tags;
}

// TODO(vojta): migrate these helpers into jasmine matchers
/**a
 * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
 * actually test if an element is displayed by the browser. Be aware!!!
 */
function isCssVisible(node) {
  var display = node.css('display');
  return !node.hasClass('ng-hide') && display != 'none';
}

function assertHidden(node) {
  if (isCssVisible(node)) {
    throw new Error('Node should be hidden but was visible: ' + angular.module.ngMock.dump(node));
  }
}

function assertVisible(node) {
  if (!isCssVisible(node)) {
    throw new Error('Node should be visible but was hidden: ' + angular.module.ngMock.dump(node));
  }
}

function provideLog($provide) {
  $provide.factory('log', function() {
      var messages = [];

      function log(msg) {
        messages.push(msg);
        return msg;
      }

      log.toString = function() {
        return messages.join('; ');
      };

      log.toArray = function() {
        return messages;
      };

      log.reset = function() {
        messages = [];
      };

      log.empty = function() {
        var currentMessages = messages;
        messages = [];
        return currentMessages;
      }

      log.fn = function(msg) {
        return function() {
          log(msg);
        };
      };

      log.$$log = true;

      return log;
    });
}

function pending() {
  dump('PENDING');
};

function trace(name) {
  dump(new Error(name).stack);
}

var karmaDump = dump;
window.dump = function () {
  karmaDump.apply(undefined, map(arguments, function(arg) {
    return angular.mock.dump(arg);
  }));
};
<commit_msg>fix(testabilityPatch): fix invocations of angular.mock.dump<commit_after>'use strict';

/**
 * Here is the problem: http://bugs.jquery.com/ticket/7292
 * basically jQuery treats change event on some browsers (IE) as a
 * special event and changes it form 'change' to 'click/keydown' and
 * few others. This horrible hack removes the special treatment
 */
if (window._jQuery) _jQuery.event.special.change = undefined;

if (window.bindJQuery) bindJQuery();

beforeEach(function() {
  // all this stuff is not needed for module tests, where jqlite and publishExternalAPI and jqLite are not global vars
  if (window.publishExternalAPI) {
    publishExternalAPI(angular);

    // workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
    // IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to
    // correct this, but only if we are not running in jqLite mode
    if (!_jqLiteMode && _jQuery !== jQuery) {
      jQuery = _jQuery;
    }

    // This resets global id counter;
    uid = ['0', '0', '0'];

    // reset to jQuery or default to us.
    bindJQuery();
  }

  angular.element(document.body).empty().removeData();
});

afterEach(function() {
  if (this.$injector) {
    var $rootScope = this.$injector.get('$rootScope');
    var $rootElement = this.$injector.get('$rootElement');
    var $log = this.$injector.get('$log');
    // release the injector
    dealoc($rootScope);
    dealoc($rootElement);

    // check $log mock
    $log.assertEmpty && $log.assertEmpty();
  }

  // complain about uncleared jqCache references
  var count = 0;

  // This line should be enabled as soon as this bug is fixed: http://bugs.jquery.com/ticket/11775
  //var cache = jqLite.cache;
  var cache = angular.element.cache;

  forEachSorted(cache, function(expando, key){
    angular.forEach(expando.data, function(value, key){
      count ++;
      if (value && value.$element) {
        dump('LEAK', key, value.$id, sortedHtml(value.$element));
      } else {
        dump('LEAK', key, angular.toJson(value));
      }
    });
  });
  if (count) {
    throw new Error('Found jqCache references that were not deallocated! count: ' + count);
  }

  // copied from Angular.js
  // we need these two methods here so that we can run module tests with wrapped angular.js
  function sortedKeys(obj) {
    var keys = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keys.push(key);
      }
    }
    return keys.sort();
  }

  function forEachSorted(obj, iterator, context) {
    var keys = sortedKeys(obj);
    for ( var i = 0; i < keys.length; i++) {
      iterator.call(context, obj[keys[i]], keys[i]);
    }
    return keys;
  }
});

function dealoc(obj) {
  var jqCache = angular.element.cache;
  if (obj) {
    if (angular.isElement(obj)) {
      cleanup(angular.element(obj));
    } else {
      for(var key in jqCache) {
        var value = jqCache[key];
        if (value.data && value.data.$scope == obj) {
          delete jqCache[key];
        }
      }
    }
  }

  function cleanup(element) {
    element.off().removeData();
    // Note:  We aren't using element.contents() here.  Under jQuery, element.contents() can fail
    // for IFRAME elements.  jQuery explicitly uses (element.contentDocument ||
    // element.contentWindow.document) and both properties are null for IFRAMES that aren't attached
    // to a document.
    var children = element[0].childNodes || [];
    for ( var i = 0; i < children.length; i++) {
      cleanup(angular.element(children[i]));
    }
  }
}

/**
 * @param {DOMElement} element
 * @param {boolean=} showNgClass
 */
function sortedHtml(element, showNgClass) {
  var html = "";
  forEach(jqLite(element), function toString(node) {

    if (node.nodeName == "#text") {
      html += node.nodeValue.
        replace(/&(\w+[&;\W])?/g, function(match, entity){return entity?match:'&';}).
        replace(/</g, '<').
        replace(/>/g, '>');
    } else if (node.nodeName == "#comment") {
      html += '<!--' + node.nodeValue + '-->';
    } else {
      html += '<' + (node.nodeName || '?NOT_A_NODE?').toLowerCase();
      var attributes = node.attributes || [];
      var attrs = [];
      var className = node.className || '';
      if (!showNgClass) {
        className = className.replace(/ng-[\w-]+\s*/g, '');
      }
      className = trim(className);
      if (className) {
        attrs.push(' class="' + className + '"');
      }
      for(var i=0; i<attributes.length; i++) {
        if (i>0 && attributes[i] == attributes[i-1])
          continue; //IE9 creates dupes. Ignore them!

        var attr = attributes[i];
        if(attr.name.match(/^ng[\:\-]/) ||
            (attr.value || attr.value == '') &&
            attr.value !='null' &&
            attr.value !='auto' &&
            attr.value !='false' &&
            attr.value !='inherit' &&
            (attr.value !='0' || attr.name =='value') &&
            attr.name !='loop' &&
            attr.name !='complete' &&
            attr.name !='maxLength' &&
            attr.name !='size' &&
            attr.name !='class' &&
            attr.name !='start' &&
            attr.name !='tabIndex' &&
            attr.name !='style' &&
            attr.name.substr(0, 6) != 'jQuery') {
          // in IE we need to check for all of these.
          if (/ng\d+/.exec(attr.name) ||
              attr.name == 'getElementById' ||
              // IE7 has `selected` in attributes
              attr.name == 'selected' ||
              // IE7 adds `value` attribute to all LI tags
              (node.nodeName == 'LI' && attr.name == 'value') ||
              // IE8 adds bogus rowspan=1 and colspan=1 to TD elements
              (node.nodeName == 'TD' && attr.name == 'rowSpan' && attr.value == '1') ||
              (node.nodeName == 'TD' && attr.name == 'colSpan' && attr.value == '1')) {
            continue;
          }

          attrs.push(' ' + attr.name + '="' + attr.value + '"');
        }
      }
      attrs.sort();
      html += attrs.join('');
      if (node.style) {
        var style = [];
        if (node.style.cssText) {
          forEach(node.style.cssText.split(';'), function(value){
            value = trim(value);
            if (value) {
              style.push(lowercase(value));
            }
          });
        }
        for(var css in node.style){
          var value = node.style[css];
          if (isString(value) && isString(css) && css != 'cssText' && value && (1*css != css)) {
            var text = lowercase(css + ': ' + value);
            if (value != 'false' && indexOf(style, text) == -1) {
              style.push(text);
            }
          }
        }
        style.sort();
        var tmp = style;
        style = [];
        forEach(tmp, function(value){
          if (!value.match(/^max[^\-]/))
            style.push(value);
        });
        if (style.length) {
          html += ' style="' + style.join('; ') + ';"';
        }
      }
      html += '>';
      var children = node.childNodes;
      for(var j=0; j<children.length; j++) {
        toString(children[j]);
      }
      html += '</' + node.nodeName.toLowerCase() + '>';
    }
  });
  return html;
}

function childrenTagsOf(element) {
  var tags = [];

  forEach(jqLite(element).children(), function(child) {
    tags.push(child.nodeName.toLowerCase());
  });

  return tags;
}

// TODO(vojta): migrate these helpers into jasmine matchers
/**a
 * This method is a cheap way of testing if css for a given node is not set to 'none'. It doesn't
 * actually test if an element is displayed by the browser. Be aware!!!
 */
function isCssVisible(node) {
  var display = node.css('display');
  return !node.hasClass('ng-hide') && display != 'none';
}

function assertHidden(node) {
  if (isCssVisible(node)) {
    throw new Error('Node should be hidden but was visible: ' + angular.mock.dump(node));
  }
}

function assertVisible(node) {
  if (!isCssVisible(node)) {
    throw new Error('Node should be visible but was hidden: ' + angular.mock.dump(node));
  }
}

function provideLog($provide) {
  $provide.factory('log', function() {
      var messages = [];

      function log(msg) {
        messages.push(msg);
        return msg;
      }

      log.toString = function() {
        return messages.join('; ');
      };

      log.toArray = function() {
        return messages;
      };

      log.reset = function() {
        messages = [];
      };

      log.empty = function() {
        var currentMessages = messages;
        messages = [];
        return currentMessages;
      }

      log.fn = function(msg) {
        return function() {
          log(msg);
        };
      };

      log.$$log = true;

      return log;
    });
}

function pending() {
  dump('PENDING');
};

function trace(name) {
  dump(new Error(name).stack);
}

var karmaDump = dump;
window.dump = function () {
  karmaDump.apply(undefined, map(arguments, function(arg) {
    return angular.mock.dump(arg);
  }));
};
<|endoftext|>


<commit_before>/*
 * MIT License
 *
 * Copyright (c) 2017-2017 Jan Dockx
 *
 * 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.
 */

/* eslint-env mocha */

const extendWithTxtStr = require('../../lib/extendWithTxtStr')
const verifyPostconditions = require('../_util/verifyPostconditions')

const attributeName = 'attribute'
const attributeValue = 'attributeValue'

describe('extendWithTxtStr', function () {
  verifyPostconditions(extendWithTxtStr)

  beforeEach(function () {
    this.preExistingValue = 'pre-existing value'
    this.subject = {
      'pre-existing': this.preExistingValue
    }
  })

  describe('simple name and value', function () {
    const txtStr = `${attributeName}=${attributeValue}`
    it(`works for txt ${txtStr}`, function () {
      extendWithTxtStr(this.subject, txtStr)
      this.subject['pre-existing'].must.equal(this.preExistingValue)
      this.subject[attributeName].must.equal(attributeValue)
      console.log(this.subject)
    })
  })
  describe('special values', function () {
    const cases = [
      '',
      'attribute value with ¨^é ∆ some weird characters',
      'attribute = value with ='
    ]
    cases.forEach(value => {
      it(`works for value ${value}`, function () {
        const txtStr = `${attributeName}=${value}`
        extendWithTxtStr(this.subject, txtStr)
        this.subject['pre-existing'].must.equal(this.preExistingValue)
        this.subject[attributeName].must.equal(value)
        console.log(this.subject)
      })
    })
  })
  describe('special attribute names', function () {
    const cases = [
      '',
      'attributeName',
      'attribute name with space',
      'pre-existing',
      'pre-Existing'
    ]
    for (let i = ' '.charCodeAt(0); i <= '~'.charCodeAt(0); i++) {
      const char = String.fromCharCode(i)
      if (char !== '=') {
        cases.push(char)
      }
    }
    cases.forEach(name => {
      const txtStr = `${name}=${attributeValue}`
      it(`works for ${txtStr}`, function () {
        extendWithTxtStr(this.subject, txtStr)
        this.subject['pre-existing'].must.equal(this.preExistingValue)
        if (name && name.toLowerCase() !== 'pre-existing') {
          this.subject[name.toLowerCase()].must.equal(attributeValue)
        }
        console.log(this.subject)
      })
    })
  })
  it(`works for boolean attribute`, function () {
    extendWithTxtStr(this.subject, attributeName)
    this.subject['pre-existing'].must.equal(this.preExistingValue)
    this.subject[attributeName].must.be.true()
    console.log(this.subject)
  })
})
<commit_msg>use chai in 1 test file - nope, this isn't it<commit_after>/*
 * MIT License
 *
 * Copyright (c) 2017-2017 Jan Dockx
 *
 * 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.
 */

/* eslint-env mocha */

require('chai').should()
const extendWithTxtStr = require('../../lib/extendWithTxtStr')
const verifyPostconditions = require('../_util/verifyPostconditions')

const attributeName = 'attribute'
const attributeValue = 'attributeValue'

describe('extendWithTxtStr', function () {
  verifyPostconditions(extendWithTxtStr)

  beforeEach(function () {
    this.preExistingValue = 'pre-existing value'
    this.subject = {
      'pre-existing': this.preExistingValue
    }
  })

  describe('simple name and value', function () {
    const txtStr = `${attributeName}=${attributeValue}`
    it(`works for txt ${txtStr}`, function () {
      extendWithTxtStr(this.subject, txtStr)
      this.subject['pre-existing'].should.equal(this.preExistingValue)
      this.subject[attributeName].should.equal(attributeValue)
      console.log(this.subject)
    })
  })
  describe('special values', function () {
    const cases = [
      '',
      'attribute value with ¨^é ∆ some weird characters',
      'attribute = value with ='
    ]
    cases.forEach(value => {
      it(`works for value ${value}`, function () {
        const txtStr = `${attributeName}=${value}`
        extendWithTxtStr(this.subject, txtStr)
        this.subject['pre-existing'].should.equal(this.preExistingValue)
        this.subject[attributeName].should.equal(value)
        console.log(this.subject)
      })
    })
  })
  describe('special attribute names', function () {
    const cases = [
      '',
      'attributeName',
      'attribute name with space',
      'pre-existing',
      'pre-Existing'
    ]
    for (let i = ' '.charCodeAt(0); i <= '~'.charCodeAt(0); i++) {
      const char = String.fromCharCode(i)
      if (char !== '=') {
        cases.push(char)
      }
    }
    cases.forEach(name => {
      const txtStr = `${name}=${attributeValue}`
      it(`works for ${txtStr}`, function () {
        extendWithTxtStr(this.subject, txtStr)
        this.subject['pre-existing'].should.equal(this.preExistingValue)
        if (name && name.toLowerCase() !== 'pre-existing') {
          this.subject[name.toLowerCase()].should.equal(attributeValue)
        }
        console.log(this.subject)
      })
    })
  })
  it(`works for boolean attribute`, function () {
    extendWithTxtStr(this.subject, attributeName)
    this.subject['pre-existing'].should.equal(this.preExistingValue)
    this.subject[attributeName].should.be.true
    console.log(this.subject)
  })
})
<|endoftext|>


<commit_before>'use strict';

const path = require('path'),
    supertest = require('supertest-as-promised'),
    express = require('express'),
    {Router} = express,
    Q = require('q'),
    _ = require('lodash');

function allArgs(spy) {
    return _.flatten(_.map(spy.calls.all(), 'args'));
}

describe('ApiLoader', () => {

    let ApiLoader,
        apiLoader,
        expressApp,
        router,
        packagePath,
        request,
        options,
        apiPackage1Prefix,
        loggerMock, apiConfig;

    beforeEach(() => {
        packagePath = './test/fixtures/main-package';
        loggerMock = {
            error: jasmine.createSpy('error')
        };
        options = {
            logger: loggerMock,
            main: packagePath,
            ignore: []
        };
        apiPackage1Prefix = '/api-package-1-namespace';

        expressApp = express();
        router = Router();

        ApiLoader = require('../../../../lib/api/loader');
        apiConfig = require('../../../../api/api-config');
        apiLoader = new ApiLoader(router, options);
        expressApp.use(router);
        request = supertest(expressApp);
    });

    it('throws an exception when invalid arguments and/or options are provided', () => {
        expect(function () {
            new ApiLoader(router, {
                main: [123]
            });
        }).toThrow();
        expect(function () {
            new ApiLoader({})
        }).toThrow();
        expect(function () {
            new ApiLoader(router, {
                logger: {
                    error: null
                }
            });
        }).toThrow();
        expect(function () {
            new ApiLoader(router, {
                directories: ['a/directory', 5]
            });
        }).toThrow();
    });

    it('does not throw if options are not provided', function () {
        expect(function () {
            new ApiLoader(router);
        }).not.toThrow();
    });

    describe('when loading routes', function () {

        it(`assigns all the valid package routes to the given router and runs the configuration functions
            exposed by package API modules`, function (done) {

            apiLoader.initialize();
            apiLoader.setAPIs();

            var promise = Q.all([
                request.get('/api-package-1-namespace/123/_api/hello').expect('Hello World!'),
                request.post('/api-package-1-namespace/123/_api/settings').expect(200),
                request.post('/api-package-1-namespace/open').expect(200),
                request.post('/api-package-2/list/mylist/items').expect(200),
                request.get('/api-package-2/list/mylist/items/123').expect(200),
                request.put('/api-package-2/list/mylist/items/123').expect(400),
                request.delete('/api-package-2/list/mylist/items/123').expect(200)
            ]);

            promise.then(done).catch(done.fail);
        });

        it(`will test if the end points assigned by api/api-config.json are working fine`, function (done) {

             apiLoader.initialize();
                  apiConfig.config({
                apiLoader: apiLoader,
                app: router
            });
            apiLoader.setAPIs();

            var promise = Q.all([
                request.get('/api-package-1-namespace/endpoints').expect(200),
                request.post('/api-package-1-namespace/endpoints').expect(200),
                request.get('/api-package-1-namespace/version').expect(200),
                request.post('/api-package-1-namespace/version').expect(404)
            ]);

            promise.then(done).catch(done.fail);
        });

        it('calls the `config` functions specified by LabShare packages', done => {
            apiLoader.initialize();
            apiLoader.setAPIs();
            apiLoader.setConfig({
                app: router
            });

            // A route set up by the 'config' package API
            request.get('/custom/api/route').expect(200).then(done).catch(done.fail);
        });

        it('logs errors for invalid routes or duplicates', function () {
            options.ignore = [];
            apiLoader = new ApiLoader(router, options);

            apiLoader.initialize();
            apiLoader.setAPIs();

            let errors = allArgs(options.logger.error).join(' ');

            expect(errors).toContain('Error: Invalid HTTP method specified for route /invalid-api-package/list/:listName/items/:id from package invalid-api-package');
            expect(errors).toContain('Error: Invalid route "{"httpMethod":"POST","middleware":[null]}" from package "invalid-api-package": path is required');
            expect(errors).toContain('Error: Invalid route "{"path":"/list/:listName/items/:id","httpMethod":"DELETE"}" from package "invalid-api-package": middleware is required');
            expect(errors).toContain('Error: Invalid route "{"path":"/documents","middleware":[null]}" from package "invalid-api-package": httpMethod is required');
        });

        it('throws exceptions for invalid routes if a logger is not provided', function () {
            options.logger = null;
            apiLoader = new ApiLoader(router, options);

            expect(function () {
                apiLoader.initialize();
            }).toThrow();
        });

        it('can ignore packages by name', function (done) {
            options.ignore = ['api-package-1'];

            apiLoader = new ApiLoader(router, options);
            apiLoader.initialize();
            apiLoader.setAPIs();

            request.post(apiPackage1Prefix + '/open').expect(404, done);
        });

        it('can load package APIs from directories specified by options.directories', function (done) {
            apiLoader = new ApiLoader(router, {
                directories: [path.join(packagePath, 'node_modules', 'api-package1')]
            });
            apiLoader.initialize();
            apiLoader.setAPIs();

            request.post(`${apiPackage1Prefix}/open`).expect(200)
                .then(done)
                .catch(done.fail);
        });

        it('does not store duplicate routers in the router', function () {
            var apiPackage1Path = path.join(packagePath, 'node_modules', 'api-package1');
            apiLoader = new ApiLoader(router, {
                directories: [apiPackage1Path, apiPackage1Path, apiPackage1Path]
            });

            apiLoader.initialize();
            apiLoader.setAPIs();

            expect(router.stack.length).toBe(1);
        });

    });

});
<commit_msg>update test to check content<commit_after>'use strict';

const path = require('path'),
    supertest = require('supertest-as-promised'),
    express = require('express'),
    {Router} = express,
    Q = require('q'),
    _ = require('lodash');

function allArgs(spy) {
    return _.flatten(_.map(spy.calls.all(), 'args'));
}

describe('ApiLoader', () => {

    let ApiLoader,
        apiLoader,
        expressApp,
        router,
        packagePath,
        request,
        options,
        apiPackage1Prefix,
        loggerMock, apiConfig;

    beforeEach(() => {
        packagePath = './test/fixtures/main-package';
        loggerMock = {
            error: jasmine.createSpy('error')
        };
        options = {
            logger: loggerMock,
            main: packagePath,
            ignore: []
        };
        apiPackage1Prefix = '/api-package-1-namespace';

        expressApp = express();
        router = Router();

        ApiLoader = require('../../../../lib/api/loader');
        apiConfig = require('../../../../api/api-config');
        apiLoader = new ApiLoader(router, options);
        expressApp.use(router);
        request = supertest(expressApp);
    });

    it('throws an exception when invalid arguments and/or options are provided', () => {
        expect(function () {
            new ApiLoader(router, {
                main: [123]
            });
        }).toThrow();
        expect(function () {
            new ApiLoader({})
        }).toThrow();
        expect(function () {
            new ApiLoader(router, {
                logger: {
                    error: null
                }
            });
        }).toThrow();
        expect(function () {
            new ApiLoader(router, {
                directories: ['a/directory', 5]
            });
        }).toThrow();
    });

    it('does not throw if options are not provided', function () {
        expect(function () {
            new ApiLoader(router);
        }).not.toThrow();
    });

    describe('when loading routes', function () {

        it(`assigns all the valid package routes to the given router and runs the configuration functions
            exposed by package API modules`, function (done) {

            apiLoader.initialize();
            apiLoader.setAPIs();

            var promise = Q.all([
                request.get('/api-package-1-namespace/123/_api/hello').expect('Hello World!'),
                request.post('/api-package-1-namespace/123/_api/settings').expect(200),
                request.post('/api-package-1-namespace/open').expect(200),
                request.post('/api-package-2/list/mylist/items').expect(200),
                request.get('/api-package-2/list/mylist/items/123').expect(200),
                request.put('/api-package-2/list/mylist/items/123').expect(400),
                request.delete('/api-package-2/list/mylist/items/123').expect(200)
            ]);

            promise.then(done).catch(done.fail);
        });

        it(`will test if the end points assigned by api/api-config.json are working fine`, function (done) {

             apiLoader.initialize();
                  apiConfig.config({
                apiLoader: apiLoader,
                app: router
            });
            apiLoader.setAPIs();

           request.get(`/api-package-1-namespace/endpoints`)
                .expect(200)
                .then(res => {

                    expect(res.text).not.toBe(null);
                    done();
                })

           request.post(`/api-package-1-namespace/endpoints`)
                .expect(200)
                .then(res => {

                    expect(res.text).not.toBe(null);
                    done();
                })
           request.get(`/api-package-1-namespace/version`)
                .expect(200)
                .then(res => {

                    expect(JSON.parse(res.text).name).toBe("api-package-1");
                    expect(JSON.parse(res.text).version).toBe('0.0.1');
                    done();
                })

           request.post(`/api-package-1-namespace/version`)
                .expect(404)
                .then(res => {
                    expect(res.error).toBeTruthy();
                    done();
                })

        });

        it('calls the `config` functions specified by LabShare packages', done => {
            apiLoader.initialize();
            apiLoader.setAPIs();
            apiLoader.setConfig({
                app: router
            });

            // A route set up by the 'config' package API
            request.get('/custom/api/route').expect(200).then(done).catch(done.fail);
        });

        it('logs errors for invalid routes or duplicates', function () {
            options.ignore = [];
            apiLoader = new ApiLoader(router, options);

            apiLoader.initialize();
            apiLoader.setAPIs();

            let errors = allArgs(options.logger.error).join(' ');

            expect(errors).toContain('Error: Invalid HTTP method specified for route /invalid-api-package/list/:listName/items/:id from package invalid-api-package');
            expect(errors).toContain('Error: Invalid route "{"httpMethod":"POST","middleware":[null]}" from package "invalid-api-package": path is required');
            expect(errors).toContain('Error: Invalid route "{"path":"/list/:listName/items/:id","httpMethod":"DELETE"}" from package "invalid-api-package": middleware is required');
            expect(errors).toContain('Error: Invalid route "{"path":"/documents","middleware":[null]}" from package "invalid-api-package": httpMethod is required');
        });

        it('throws exceptions for invalid routes if a logger is not provided', function () {
            options.logger = null;
            apiLoader = new ApiLoader(router, options);

            expect(function () {
                apiLoader.initialize();
            }).toThrow();
        });

        it('can ignore packages by name', function (done) {
            options.ignore = ['api-package-1'];

            apiLoader = new ApiLoader(router, options);
            apiLoader.initialize();
            apiLoader.setAPIs();

            request.post(apiPackage1Prefix + '/open').expect(404, done);
        });

        it('can load package APIs from directories specified by options.directories', function (done) {
            apiLoader = new ApiLoader(router, {
                directories: [path.join(packagePath, 'node_modules', 'api-package1')]
            });
            apiLoader.initialize();
            apiLoader.setAPIs();

            request.post(`${apiPackage1Prefix}/open`).expect(200)
                .then(done)
                .catch(done.fail);
        });

        it('does not store duplicate routers in the router', function () {
            var apiPackage1Path = path.join(packagePath, 'node_modules', 'api-package1');
            apiLoader = new ApiLoader(router, {
                directories: [apiPackage1Path, apiPackage1Path, apiPackage1Path]
            });

            apiLoader.initialize();
            apiLoader.setAPIs();

            expect(router.stack.length).toBe(1);
        });

    });

});
<|endoftext|>


<commit_before>import { expect } from 'chai';

import {
  launchKernel,
  shutdownKernel,
  forceShutdownKernel,
} from '../../../src/notebook/api/kernel';

describe('the circle of life', () => {
  it('is available for creating and destroying kernels', () => {
    const kernelPromise = launchKernel('python2');

    return kernelPromise.then(kernel => {
      expect(kernel.channels).to.not.be.undefined;
      return shutdownKernel(kernel).then(() => {
        expect(kernel.channels).to.be.undefined;
      });
    })
  });
  it('is available for creating and force shutting down kernels', () => {
    const kernelPromise = launchKernel('python2');

    return kernelPromise.then(kernel => {
      expect(kernel.channels).to.not.be.undefined;
      forceShutdownKernel(kernel);
      expect(kernel.channels).to.be.undefined;
    })
  });
});
<commit_msg>Add tests for kernel interrupt<commit_after>import { expect } from 'chai';

import {
  launchKernel,
  shutdownKernel,
  forceShutdownKernel,
} from '../../../src/notebook/api/kernel';

import reducers from '../../../src/notebook/reducers';
import * as constants from '../../../src/notebook/constants';
import { AppRecord } from '../../../src/notebook/records';

describe('the circle of life', () => {
  it('is available for creating and destroying kernels', () => {
    const kernelPromise = launchKernel('python2');

    return kernelPromise.then(kernel => {
      expect(kernel.channels).to.not.be.undefined;
      return shutdownKernel(kernel).then(() => {
        expect(kernel.channels).to.be.undefined;
      });
    })
  });
  it('is available for creating and force shutting down kernels', () => {
    const kernelPromise = launchKernel('python2');

    return kernelPromise.then(kernel => {
      expect(kernel.channels).to.not.be.undefined;
      forceShutdownKernel(kernel);
      expect(kernel.channels).to.be.undefined;
    })
  });
  it('can be interrupted', () => {
    const kernelPromise = launchKernel('python2');

    return kernelPromise.then(kernel => {
      const originalState = {
        app: new AppRecord(kernel),
      };

      const action = {
        type: constants.INTERRUPT_KERNEL,
      };

      const state = reducers(originalState, action);
      expect(state.app.spawn.connected).to.be.false;
      shutdownKernel(kernel);
    });
  });
});
<|endoftext|>