mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-04-29 05:15:38 +08:00
chore: reorganize test helper files under test/helpers
This commit is contained in:
266
test/helpers/matchers.js
Normal file
266
test/helpers/matchers.js
Normal file
@@ -0,0 +1,266 @@
|
||||
beforeEach(function() {
|
||||
|
||||
function cssMatcher(presentClasses, absentClasses) {
|
||||
return function() {
|
||||
var element = angular.element(this.actual);
|
||||
var present = true;
|
||||
var absent = false;
|
||||
|
||||
angular.forEach(presentClasses.split(' '), function(className){
|
||||
present = present && element.hasClass(className);
|
||||
});
|
||||
|
||||
angular.forEach(absentClasses.split(' '), function(className){
|
||||
absent = absent || element.hasClass(className);
|
||||
});
|
||||
|
||||
this.message = function() {
|
||||
return "Expected to have " + presentClasses +
|
||||
(absentClasses ? (" and not have " + absentClasses + "" ) : "") +
|
||||
" but had " + element[0].className + ".";
|
||||
};
|
||||
return present && !absent;
|
||||
};
|
||||
}
|
||||
|
||||
function indexOf(array, obj) {
|
||||
for ( var i = 0; i < array.length; i++) {
|
||||
if (obj === array[i]) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function isNgElementHidden(element) {
|
||||
return angular.element(element).hasClass('ng-hide');
|
||||
};
|
||||
|
||||
this.addMatchers({
|
||||
toBeInvalid: cssMatcher('ng-invalid', 'ng-valid'),
|
||||
toBeValid: cssMatcher('ng-valid', 'ng-invalid'),
|
||||
toBeDirty: cssMatcher('ng-dirty', 'ng-pristine'),
|
||||
toBePristine: cssMatcher('ng-pristine', 'ng-dirty'),
|
||||
toBeShown: function() {
|
||||
this.message = valueFn(
|
||||
"Expected element " + (this.isNot ? "": "not ") + "to have 'ng-hide' class");
|
||||
return !isNgElementHidden(this.actual);
|
||||
},
|
||||
toBeHidden: function() {
|
||||
this.message = valueFn(
|
||||
"Expected element " + (this.isNot ? "not ": "") + "to have 'ng-hide' class");
|
||||
return isNgElementHidden(this.actual);
|
||||
},
|
||||
|
||||
toEqual: function(expected) {
|
||||
if (this.actual && this.actual.$$log) {
|
||||
this.actual = (typeof expected === 'string')
|
||||
? this.actual.toString()
|
||||
: this.actual.toArray();
|
||||
}
|
||||
return jasmine.Matchers.prototype.toEqual.call(this, expected);
|
||||
},
|
||||
|
||||
toEqualData: function(expected) {
|
||||
return angular.equals(this.actual, expected);
|
||||
},
|
||||
|
||||
toEqualError: function(message) {
|
||||
this.message = function() {
|
||||
var expected;
|
||||
if (this.actual.message && this.actual.name == 'Error') {
|
||||
expected = toJson(this.actual.message);
|
||||
} else {
|
||||
expected = toJson(this.actual);
|
||||
}
|
||||
return "Expected " + expected + " to be an Error with message " + toJson(message);
|
||||
};
|
||||
return this.actual.name == 'Error' && this.actual.message == message;
|
||||
},
|
||||
|
||||
toMatchError: function(messageRegexp) {
|
||||
this.message = function() {
|
||||
var expected;
|
||||
if (this.actual.message && this.actual.name == 'Error') {
|
||||
expected = angular.toJson(this.actual.message);
|
||||
} else {
|
||||
expected = angular.toJson(this.actual);
|
||||
}
|
||||
return "Expected " + expected + " to match an Error with message " + angular.toJson(messageRegexp);
|
||||
};
|
||||
return this.actual.name == 'Error' && messageRegexp.test(this.actual.message);
|
||||
},
|
||||
|
||||
toHaveBeenCalledOnce: function() {
|
||||
if (arguments.length > 0) {
|
||||
throw new Error('toHaveBeenCalledOnce does not take arguments, use toHaveBeenCalledWith');
|
||||
}
|
||||
|
||||
if (!jasmine.isSpy(this.actual)) {
|
||||
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
|
||||
}
|
||||
|
||||
this.message = function() {
|
||||
var msg = 'Expected spy ' + this.actual.identity + ' to have been called once, but was ',
|
||||
count = this.actual.callCount;
|
||||
return [
|
||||
count === 0 ? msg + 'never called.' :
|
||||
msg + 'called ' + count + ' times.',
|
||||
msg.replace('to have', 'not to have') + 'called once.'
|
||||
];
|
||||
};
|
||||
|
||||
return this.actual.callCount == 1;
|
||||
},
|
||||
|
||||
|
||||
toHaveBeenCalledOnceWith: function() {
|
||||
var expectedArgs = jasmine.util.argsToArray(arguments);
|
||||
|
||||
if (!jasmine.isSpy(this.actual)) {
|
||||
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
|
||||
}
|
||||
|
||||
this.message = function() {
|
||||
if (this.actual.callCount != 1) {
|
||||
if (this.actual.callCount == 0) {
|
||||
return [
|
||||
'Expected spy ' + this.actual.identity + ' to have been called once with ' +
|
||||
jasmine.pp(expectedArgs) + ' but it was never called.',
|
||||
'Expected spy ' + this.actual.identity + ' not to have been called with ' +
|
||||
jasmine.pp(expectedArgs) + ' but it was.'
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'Expected spy ' + this.actual.identity + ' to have been called once with ' +
|
||||
jasmine.pp(expectedArgs) + ' but it was called ' + this.actual.callCount + ' times.',
|
||||
'Expected spy ' + this.actual.identity + ' not to have been called once with ' +
|
||||
jasmine.pp(expectedArgs) + ' but it was.'
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'Expected spy ' + this.actual.identity + ' to have been called once with ' +
|
||||
jasmine.pp(expectedArgs) + ' but was called with ' + jasmine.pp(this.actual.argsForCall),
|
||||
'Expected spy ' + this.actual.identity + ' not to have been called once with ' +
|
||||
jasmine.pp(expectedArgs) + ' but was called with ' + jasmine.pp(this.actual.argsForCall)
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
return this.actual.callCount === 1 && this.env.contains_(this.actual.argsForCall, expectedArgs);
|
||||
},
|
||||
|
||||
|
||||
toBeOneOf: function() {
|
||||
return indexOf(arguments, this.actual) !== -1;
|
||||
},
|
||||
|
||||
toHaveClass: function(clazz) {
|
||||
this.message = function() {
|
||||
return "Expected '" + angular.mock.dump(this.actual) + "' to have class '" + clazz + "'.";
|
||||
};
|
||||
return this.actual.hasClass ?
|
||||
this.actual.hasClass(clazz) :
|
||||
angular.element(this.actual).hasClass(clazz);
|
||||
},
|
||||
|
||||
toThrowMatching: function(expected) {
|
||||
return jasmine.Matchers.prototype.toThrow.call(this, expected);
|
||||
},
|
||||
|
||||
toThrowMinErr: function(namespace, code, content) {
|
||||
var result,
|
||||
exception,
|
||||
exceptionMessage = '',
|
||||
escapeRegexp = function (str) {
|
||||
// This function escapes all special regex characters.
|
||||
// We use it to create matching regex from arbitrary strings.
|
||||
// http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
|
||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
},
|
||||
codeRegex = new RegExp('^\\[' + escapeRegexp(namespace) + ':' + escapeRegexp(code) + '\\]'),
|
||||
not = this.isNot ? "not " : "",
|
||||
regex = jasmine.isA_("RegExp", content) ? content :
|
||||
isDefined(content) ? new RegExp(escapeRegexp(content)) : undefined;
|
||||
|
||||
if(!isFunction(this.actual)) {
|
||||
throw new Error('Actual is not a function');
|
||||
}
|
||||
|
||||
try {
|
||||
this.actual();
|
||||
} catch (e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
if (exception) {
|
||||
exceptionMessage = exception.message || exception;
|
||||
}
|
||||
|
||||
this.message = function () {
|
||||
return "Expected function " + not + "to throw " +
|
||||
namespace + "MinErr('" + code + "')" +
|
||||
(regex ? " matching " + regex.toString() : "") +
|
||||
(exception ? ", but it threw " + exceptionMessage : ".");
|
||||
};
|
||||
|
||||
result = codeRegex.test(exceptionMessage);
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (isDefined(regex)) {
|
||||
return regex.test(exceptionMessage);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// TODO(vojta): remove this once Jasmine in Karma gets updated
|
||||
// https://github.com/pivotal/jasmine/blob/c40b64a24c607596fa7488f2a0ddb98d063c872a/src/core/Matchers.js#L217-L246
|
||||
// This toThrow supports RegExps.
|
||||
jasmine.Matchers.prototype.toThrow = function(expected) {
|
||||
var result = false;
|
||||
var exception, exceptionMessage;
|
||||
if (typeof this.actual != 'function') {
|
||||
throw new Error('Actual is not a function');
|
||||
}
|
||||
try {
|
||||
this.actual();
|
||||
} catch (e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
if (exception) {
|
||||
exceptionMessage = exception.message || exception;
|
||||
result = (isUndefined(expected) || this.env.equals_(exceptionMessage, expected.message || expected) || (jasmine.isA_("RegExp", expected) && expected.test(exceptionMessage)));
|
||||
}
|
||||
|
||||
var not = this.isNot ? "not " : "";
|
||||
var regexMatch = jasmine.isA_("RegExp", expected) ? " an exception matching" : "";
|
||||
|
||||
this.message = function() {
|
||||
if (exception) {
|
||||
return ["Expected function " + not + "to throw" + regexMatch, expected ? expected.message || expected : "an exception", ", but it threw", exceptionMessage].join(' ');
|
||||
} else {
|
||||
return "Expected function to throw an exception.";
|
||||
}
|
||||
};
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create jasmine.Spy on given method, but ignore calls without arguments
|
||||
* This is helpful when need to spy only setter methods and ignore getters
|
||||
*/
|
||||
function spyOnlyCallsWithArgs(obj, method) {
|
||||
var spy = spyOn(obj, method);
|
||||
obj[method] = function() {
|
||||
if (arguments.length) return spy.apply(this, arguments);
|
||||
return spy.originalValue.apply(this);
|
||||
};
|
||||
return spy;
|
||||
}
|
||||
28
test/helpers/privateMocks.js
Normal file
28
test/helpers/privateMocks.js
Normal file
@@ -0,0 +1,28 @@
|
||||
function createMockStyleSheet(doc, wind) {
|
||||
doc = doc ? doc[0] : 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) {
|
||||
try {
|
||||
ss.insertRule(selector + '{ ' + styles + '}', 0);
|
||||
}
|
||||
catch(e) {
|
||||
try {
|
||||
ss.addRule(selector, styles);
|
||||
}
|
||||
catch(e) {}
|
||||
}
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
head.removeChild(node);
|
||||
}
|
||||
};
|
||||
};
|
||||
36
test/helpers/privateMocksSpec.js
Normal file
36
test/helpers/privateMocksSpec.js
Normal file
@@ -0,0 +1,36 @@
|
||||
describe('private mocks', function() {
|
||||
describe('createMockStyleSheet', function() {
|
||||
|
||||
it('should allow custom styles to be created and removed when the stylesheet is destroyed',
|
||||
inject(function($compile, $document, $window, $rootElement, $rootScope) {
|
||||
|
||||
var doc = $document[0];
|
||||
var count = doc.styleSheets.length;
|
||||
var stylesheet = createMockStyleSheet($document, $window);
|
||||
expect(doc.styleSheets.length).toBe(count + 1);
|
||||
|
||||
jqLite(doc.body).append($rootElement);
|
||||
|
||||
var elm = $compile('<div class="padded">...</div>')($rootScope);
|
||||
$rootElement.append(elm);
|
||||
|
||||
expect(getStyle(elm, 'paddingTop')).toBe('0px');
|
||||
|
||||
stylesheet.addRule('.padded', 'padding-top:2px');
|
||||
|
||||
expect(getStyle(elm, 'paddingTop')).toBe('2px');
|
||||
|
||||
stylesheet.destroy();
|
||||
|
||||
expect(getStyle(elm, 'paddingTop')).toBe('0px');
|
||||
|
||||
function getStyle(element, key) {
|
||||
var node = element[0];
|
||||
return node.currentStyle ?
|
||||
node.currentStyle[key] :
|
||||
$window.getComputedStyle(node)[key];
|
||||
};
|
||||
}));
|
||||
|
||||
});
|
||||
});
|
||||
297
test/helpers/testabilityPatch.js
Normal file
297
test/helpers/testabilityPatch.js
Normal file
@@ -0,0 +1,297 @@
|
||||
'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).html('').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;
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
}));
|
||||
};
|
||||
Reference in New Issue
Block a user