angular-material-mocks.js 4.71 KB
Newer Older
Thitichaipun Wutthisak committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
/**
 *
 * Angular-Material-Mocks
 *
 * Developers interested in running their own custom unit tests WITH angular-material.js loaded...
 * must also include this *mocks* file. Similar to `angular-mocks.js`, `angular-material-mocks.js`
 * will override and disable specific Angular Material performance settings:
 *
 *  - Disabled Theme CSS rule generations
 *  - Forces $mdAria.expectWithText() to be synchronous
 *  - Mocks $$rAF.throttle()
 *  - Captures flush exceptions from $$rAF
 *
 */
(function(window, angular, undefined) {

'use strict';

/**
 * @ngdoc module
 * @name ngMaterial-mock
 * @packageName angular-material-mocks
 *
 * @description
 *
 * The `ngMaterial-mock` module provides support
 *
 */
angular.module('ngMaterial-mock', [
  'ngMock',
  'ngAnimateMock',
  'material.core'
  ])
  .config(['$provide', function($provide) {

    $provide.factory('$material', ['$animate', '$timeout', function($animate, $timeout) {
      return {
        flushOutstandingAnimations: function() {
          // this code is placed in a try-catch statement
          // since 1.3 and 1.4 handle their animations differently
          // and there may be situations where follow-up animations
          // are run in one version and not the other
          try { $animate.flush(); } catch(e) {}
        },
        flushInterimElement: function() {
          this.flushOutstandingAnimations();
          $timeout.flush();
          this.flushOutstandingAnimations();
          $timeout.flush();
          this.flushOutstandingAnimations();
          $timeout.flush();
        }
      };
    }]);

    /**
      * Angular Material dynamically generates Style tags
      * based on themes and palletes; for each ng-app.
      *
      * For testing, we want to disable generation and
      * <style> DOM injections. So we clear the huge THEME
      * styles while testing...
      */
     $provide.constant('$MD_THEME_CSS', '/**/');

    /**
     * Add throttle() and wrap .flush() to catch `no callbacks present`
     * errors
     */
    $provide.decorator('$$rAF', function throttleInjector($delegate){

      $delegate.throttle = function(cb) {
        return function() {
          cb.apply(this, arguments);
        };
      };

      var ngFlush = $delegate.flush;
      $delegate.flush = function() {
        try      { ngFlush();  }
        catch(e) { ;           }
      };

      return $delegate;
    });

    /**
     * Capture $timeout.flush() errors: "No deferred tasks to be flushed"
     * errors
     */
    $provide.decorator('$timeout', function throttleInjector($delegate){

      var ngFlush = $delegate.flush;
      $delegate.flush = function() {
          var args = Array.prototype.slice.call(arguments);
          try      { ngFlush.apply($delegate, args);  }
          catch(e) { ;           }
      };

      return $delegate;
    });

  }])

  /**
   * Stylesheet Mocks used by `animateCss.spec.js`
   */
  window.createMockStyleSheet = function createMockStyleSheet(doc, wind) {
    doc = doc ? doc[0] : window.document;
    wind = wind || window;

    var node = doc.createElement('style');
    var head = doc.getElementsByTagName('head')[0];
    head.appendChild(node);

    var ss = doc.styleSheets[doc.styleSheets.length - 1];

    return {
      addRule: function(selector, styles) {
        styles = addVendorPrefix(styles);

        try {
          ss.insertRule(selector + '{ ' + styles + '}', 0);
        }
        catch (e) {
          try {
            ss.addRule(selector, styles);
          }
          catch (e2) {}
        }
      },

      destroy: function() {
        head.removeChild(node);
      }
    };

    /**
     * Decompose styles, attached specific vendor prefixes
     * and recompose...
     * e.g.
     *    'transition:0.5s linear all; font-size:100px;'
     * becomes
     *    '-webkit-transition:0.5s linear all; transition:0.5s linear all; font-size:100px;'
     */
    function addVendorPrefix(styles) {
      var cache = { };

      // Decompose into cache registry
      styles
        .match(/([\-A-Za-z]*)\w\:\w*([A-Za-z0-9\.\-\s]*)/gi)
        .forEach(function(style){
          var pair = style.split(":");
          var key = pair[0];

          switch(key) {
            case 'transition':
            case 'transform':
            case 'animation':
            case 'transition-duration':
            case 'animation-duration':
              cache[key] = cache['-webkit-' + key] = pair[1];
              break;
            default:
              cache[key] = pair[1];
          }
        });

        // Recompose full style object (as string)
        styles = "";
        angular.forEach(cache, function(value, key) {
          styles = styles + key + ":" + value + "; ";
        });

        return styles;
    }

  };

})(window, window.angular);