aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/ng/compileSpec.js90
-rw-r--r--test/ng/directive/booleanAttrsSpec.js104
-rw-r--r--test/ng/directive/ngBindSpec.js48
-rw-r--r--test/ng/directive/ngIncludeSpec.js50
-rw-r--r--test/ng/directive/ngSrcSpec.js44
-rw-r--r--test/ng/interpolateSpec.js59
-rw-r--r--test/ng/sceSpecs.js347
-rw-r--r--test/ng/urlUtilsSpec.js18
-rw-r--r--test/ngRoute/routeSpec.js30
-rw-r--r--test/testabilityPatch.js7
10 files changed, 739 insertions, 58 deletions
diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js
index c7821878..1f5aae95 100755
--- a/test/ng/compileSpec.js
+++ b/test/ng/compileSpec.js
@@ -681,9 +681,17 @@ describe('$compile', function() {
restrict: 'CAM', templateUrl: 'hello.html', transclude: true
}));
directive('cau', valueFn({
- restrict: 'CAM', templateUrl:'cau.html'
+ restrict: 'CAM', templateUrl: 'cau.html'
}));
-
+ directive('crossDomainTemplate', valueFn({
+ restrict: 'CAM', templateUrl: 'http://example.com/should-not-load.html'
+ }));
+ directive('trustedTemplate', function($sce) { return {
+ restrict: 'CAM',
+ templateUrl: function() {
+ return $sce.trustAsResourceUrl('http://example.com/trusted-template.html');
+ }};
+ });
directive('cError', valueFn({
restrict: 'CAM',
templateUrl:'error.html',
@@ -735,6 +743,24 @@ describe('$compile', function() {
}
));
+ it('should not load cross domain templates by default', inject(
+ function($compile, $rootScope, $templateCache, $sce) {
+ expect(function() {
+ $templateCache.put('http://example.com/should-not-load.html', 'Should not load even if in cache.');
+ $compile('<div class="crossDomainTemplate"></div>')($rootScope);
+ }).toThrow('[$sce:isecrurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL: http://example.com/should-not-load.html');
+ }));
+
+ it('should load cross domain templates when trusted', inject(
+ function($compile, $httpBackend, $rootScope, $sce) {
+ $httpBackend.expect('GET', 'http://example.com/trusted-template.html').respond('<span>example.com/trusted_template_contents</span>');
+ element = $compile('<div class="trustedTemplate"></div>')($rootScope);
+ expect(sortedHtml(element)).
+ toEqual('<div class="trustedTemplate"></div>');
+ $httpBackend.flush();
+ expect(sortedHtml(element)).
+ toEqual('<div class="trustedTemplate"><span>example.com/trusted_template_contents</span></div>');
+ }));
it('should append template via $http and cache it in $templateCache', inject(
function($compile, $httpBackend, $templateCache, $rootScope, $browser) {
@@ -1521,6 +1547,16 @@ describe('$compile', function() {
expect(element.attr('name')).toEqual('attr: angular');
}));
+ describe('SCE values', function() {
+ it('should resolve compile and link both attribute and text bindings', inject(
+ function($rootScope, $compile, $sce) {
+ $rootScope.name = $sce.trustAsHtml('angular');
+ element = $compile('<div name="attr: {{name}}">text: {{name}}</div>')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toEqual('text: angular');
+ expect(element.attr('name')).toEqual('attr: angular');
+ }));
+ });
it('should decorate the binding with ng-binding and interpolation function', inject(
function($compile, $rootScope) {
@@ -2625,12 +2661,16 @@ describe('$compile', function() {
});
- describe('img[src] sanitization', function() {
- it('should NOT require trusted values for img src', inject(function($rootScope, $compile) {
+ describe('img[src] sanitization', function($sce) {
+ it('should NOT require trusted values for img src', inject(function($rootScope, $compile, $sce) {
element = $compile('<img src="{{testUrl}}"></img>')($rootScope);
$rootScope.testUrl = 'http://example.com/image.png';
$rootScope.$digest();
expect(element.attr('src')).toEqual('http://example.com/image.png');
+ // But it should accept trusted values anyway.
+ $rootScope.testUrl = $sce.trustAsUrl('http://example.com/image2.png');
+ $rootScope.$digest();
+ expect(element.attr('src')).toEqual('http://example.com/image2.png');
}));
it('should sanitize javascript: urls', inject(function($compile, $rootScope) {
@@ -2965,6 +3005,48 @@ describe('$compile', function() {
}));
});
+ describe('iframe[src]', function() {
+ it('should pass through src attributes for the same domain', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = "different_page";
+ $rootScope.$apply();
+ expect(element.attr('src')).toEqual('different_page');
+ }));
+
+ it('should clear out src attributes for a different domain', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = "http://a.different.domain.example.com";
+ expect(function() { $rootScope.$apply() }).toThrow(
+ "[$interpolate:interr] Can't interpolate: {{testUrl}}\nError: [$sce:isecrurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: " +
+ "http://a.different.domain.example.com");
+ }));
+
+ it('should clear out JS src attributes', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = "javascript:alert(1);";
+ expect(function() { $rootScope.$apply() }).toThrow(
+ "[$interpolate:interr] Can't interpolate: {{testUrl}}\nError: [$sce:isecrurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: " +
+ "javascript:alert(1);");
+ }));
+
+ it('should clear out non-resource_url src attributes', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()");
+ expect($rootScope.$apply).toThrow(
+ "[$interpolate:interr] Can't interpolate: {{testUrl}}\nError: [$sce:isecrurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: javascript:doTrustedStuff()");
+ }));
+
+ it('should pass through $sce.trustAs() values in src attributes', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = $sce.trustAsResourceUrl("javascript:doTrustedStuff()");
+ $rootScope.$apply();
+
+ expect(element.attr('src')).toEqual('javascript:doTrustedStuff()');
+ }));
+ });
describe('ngAttr* attribute binding', function() {
diff --git a/test/ng/directive/booleanAttrsSpec.js b/test/ng/directive/booleanAttrsSpec.js
index be2dfb60..93e8cc20 100644
--- a/test/ng/directive/booleanAttrsSpec.js
+++ b/test/ng/directive/booleanAttrsSpec.js
@@ -102,61 +102,99 @@ describe('boolean attr directives', function() {
describe('ngSrc', function() {
- it('should interpolate the expression and bind to src', inject(function($compile, $rootScope) {
+ it('should interpolate the expression and bind to src with raw same-domain value',
+ inject(function($compile, $rootScope) {
+ var element = $compile('<div ng-src="{{id}}"></div>')($rootScope);
+
+ $rootScope.$digest();
+ expect(element.attr('src')).toBeUndefined();
+
+ $rootScope.$apply(function() {
+ $rootScope.id = '/somewhere/here';
+ });
+ expect(element.attr('src')).toEqual('/somewhere/here');
+
+ dealoc(element);
+ }));
+
+
+ it('should interpolate the expression and bind to src with a trusted value', inject(function($compile, $rootScope, $sce) {
var element = $compile('<div ng-src="{{id}}"></div>')($rootScope);
$rootScope.$digest();
expect(element.attr('src')).toBeUndefined();
$rootScope.$apply(function() {
- $rootScope.id = 1;
+ $rootScope.id = $sce.trustAsResourceUrl('http://somewhere');
});
- expect(element.attr('src')).toEqual('1');
+ expect(element.attr('src')).toEqual('http://somewhere');
dealoc(element);
}));
- describe('isTrustedContext', function() {
- it('should NOT interpolate a multi-part expression for non-img src attribute', inject(function($compile, $rootScope) {
- expect(function() {
- var element = $compile('<div ng-src="some/{{id}}"></div>')($rootScope);
- dealoc(element);
- }).toThrow(
- "[$interpolate:noconcat] Error while interpolating: some/{{id}}\nYou may not use " +
- "multiple expressions when interpolating this expression.");
- }));
- it('should interpolate a multi-part expression for regular attributes', inject(function($compile, $rootScope) {
- var element = $compile('<div foo="some/{{id}}"></div>')($rootScope);
- $rootScope.$digest();
- expect(element.attr('foo')).toBe('some/');
+ it('should NOT interpolate a multi-part expression for non-img src attribute', inject(function($compile, $rootScope) {
+ expect(function() {
+ var element = $compile('<div ng-src="some/{{id}}"></div>')($rootScope);
+ dealoc(element);
+ }).toThrow(
+ "[$interpolate:noconcat] Error while interpolating: some/{{id}}\nStrict " +
+ "Contextual Escaping disallows interpolations that concatenate multiple expressions " +
+ "when a trusted value is required. See http://docs.angularjs.org/api/ng.$sce");
+ }));
+
+
+ it('should interpolate a multi-part expression for regular attributes', inject(function($compile, $rootScope) {
+ var element = $compile('<div foo="some/{{id}}"></div>')($rootScope);
+ $rootScope.$digest();
+ expect(element.attr('foo')).toBe('some/');
+ $rootScope.$apply(function() {
+ $rootScope.id = 1;
+ });
+ expect(element.attr('foo')).toEqual('some/1');
+ }));
+
+
+ it('should NOT interpolate a wrongly typed expression', inject(function($compile, $rootScope, $sce) {
+ expect(function() {
+ var element = $compile('<div ng-src="{{id}}"></div>')($rootScope);
$rootScope.$apply(function() {
- $rootScope.id = 1;
+ $rootScope.id = $sce.trustAsUrl('http://somewhere');
});
- expect(element.attr('foo')).toEqual('some/1');
- }));
+ element.attr('src');
+ }).toThrow(
+ "[$interpolate:interr] Can't interpolate: {{id}}\nError: [$sce:isecrurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: http://somewhere");
+ }));
- });
if (msie) {
it('should update the element property as well as the attribute', inject(
- function($compile, $rootScope) {
- // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
- // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
- // to set the property as well to achieve the desired effect
+ function($compile, $rootScope, $sce) {
+ // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
+ // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
+ // to set the property as well to achieve the desired effect
- var element = $compile('<div ng-src="{{id}}"></div>')($rootScope);
+ var element = $compile('<div ng-src="{{id}}"></div>')($rootScope);
- $rootScope.$digest();
- expect(element.prop('src')).toBeUndefined();
+ $rootScope.$digest();
+ expect(element.prop('src')).toBeUndefined();
+ dealoc(element);
- $rootScope.$apply(function() {
- $rootScope.id = 1;
- });
- expect(element.prop('src')).toEqual('1');
+ element = $compile('<div ng-src="some/"></div>')($rootScope);
- dealoc(element);
- }));
+ $rootScope.$digest();
+ expect(element.prop('src')).toEqual('some/');
+ dealoc(element);
+
+ element = $compile('<div ng-src="{{id}}"></div>')($rootScope);
+ $rootScope.$apply(function() {
+ $rootScope.id = $sce.trustAsResourceUrl('http://somewhere');
+ });
+ expect(element.prop('src')).toEqual('http://somewhere');
+
+ dealoc(element);
+ }));
}
});
diff --git a/test/ng/directive/ngBindSpec.js b/test/ng/directive/ngBindSpec.js
index da291fa4..1d8f8ef4 100644
--- a/test/ng/directive/ngBindSpec.js
+++ b/test/ng/directive/ngBindSpec.js
@@ -69,11 +69,47 @@ describe('ngBind*', function() {
describe('ngBindHtmlUnsafe', function() {
- it('should set unsafe html', inject(function($rootScope, $compile) {
- element = $compile('<div ng-bind-html-unsafe="html"></div>')($rootScope);
- $rootScope.html = '<div onclick="">hello</div>';
- $rootScope.$digest();
- expect(angular.lowercase(element.html())).toEqual('<div onclick="">hello</div>');
- }));
+ function configureSce(enabled) {
+ module(function($provide, $sceProvider) {
+ $sceProvider.enabled(enabled);
+ });
+ };
+
+ describe('SCE disabled', function() {
+ beforeEach(function() {configureSce(false)});
+
+ it('should set unsafe html', inject(function($rootScope, $compile) {
+ element = $compile('<div ng-bind-html-unsafe="html"></div>')($rootScope);
+ $rootScope.html = '<div onclick="">hello</div>';
+ $rootScope.$digest();
+ expect(angular.lowercase(element.html())).toEqual('<div onclick="">hello</div>');
+ }));
+ });
+
+
+ describe('SCE enabled', function() {
+ beforeEach(function() {configureSce(true)});
+
+ it('should NOT set unsafe html for untrusted values', inject(function($rootScope, $compile) {
+ element = $compile('<div ng-bind-html-unsafe="html"></div>')($rootScope);
+ $rootScope.html = '<div onclick="">hello</div>';
+ expect($rootScope.$digest).toThrow();
+ }));
+
+ it('should NOT set unsafe html for wrongly typed values', inject(function($rootScope, $compile, $sce) {
+ element = $compile('<div ng-bind-html-unsafe="html"></div>')($rootScope);
+ $rootScope.html = $sce.trustAsCss('<div onclick="">hello</div>');
+ expect($rootScope.$digest).toThrow();
+ }));
+
+ it('should set unsafe html for trusted values', inject(function($rootScope, $compile, $sce) {
+ element = $compile('<div ng-bind-html-unsafe="html"></div>')($rootScope);
+ $rootScope.html = $sce.trustAsHtml('<div onclick="">hello</div>');
+ $rootScope.$digest();
+ expect(angular.lowercase(element.html())).toEqual('<div onclick="">hello</div>');
+ }));
+
+ });
+
});
});
diff --git a/test/ng/directive/ngIncludeSpec.js b/test/ng/directive/ngIncludeSpec.js
index 93709431..6cb78755 100644
--- a/test/ng/directive/ngIncludeSpec.js
+++ b/test/ng/directive/ngIncludeSpec.js
@@ -3,7 +3,6 @@
describe('ngInclude', function() {
var element;
-
afterEach(function(){
dealoc(element);
});
@@ -16,7 +15,29 @@ describe('ngInclude', function() {
}
- it('should include on external file', inject(putIntoCache('myUrl', '{{name}}'),
+ it('should trust and use literal urls', inject(function(
+ $rootScope, $httpBackend, $compile) {
+ element = $compile('<div ng-include="\'url\'"></div>')($rootScope);
+ $httpBackend.expect('GET', 'url').respond('template text');
+ $rootScope.$digest();
+ $httpBackend.flush();
+ expect(element.text()).toEqual('template text');
+ dealoc($rootScope);
+ }));
+
+
+ it('should trust and use trusted urls', inject(function($rootScope, $httpBackend, $compile, $sce) {
+ element = $compile('<div ng-include="fooUrl"></div>')($rootScope);
+ $httpBackend.expect('GET', 'http://foo.bar/url').respond('template text');
+ $rootScope.fooUrl = $sce.trustAsResourceUrl('http://foo.bar/url');
+ $rootScope.$digest();
+ $httpBackend.flush();
+ expect(element.text()).toEqual('template text');
+ dealoc($rootScope);
+ }));
+
+
+ it('should include an external file', inject(putIntoCache('myUrl', '{{name}}'),
function($rootScope, $compile) {
element = jqLite('<ng:include src="url"></ng:include>');
jqLite(document.body).append(element);
@@ -42,6 +63,29 @@ describe('ngInclude', function() {
}));
+ it('should NOT use untrusted expressions ', inject(putIntoCache('myUrl', '{{name}} text'),
+ function($rootScope, $compile, $sce) {
+ element = jqLite('<ng:include src="url"></ng:include>');
+ jqLite(document.body).append(element);
+ element = $compile(element)($rootScope);
+ $rootScope.name = 'chirayu';
+ $rootScope.url = 'myUrl';
+ expect($rootScope.$digest).toThrow();
+ jqLite(document.body).html('');
+ }));
+
+
+ it('should NOT use mistyped expressions ', inject(putIntoCache('myUrl', '{{name}} text'),
+ function($rootScope, $compile, $sce) {
+ element = jqLite('<ng:include src="url"></ng:include>');
+ jqLite(document.body).append(element);
+ element = $compile(element)($rootScope);
+ $rootScope.name = 'chirayu';
+ $rootScope.url = $sce.trustAsUrl('myUrl');
+ expect($rootScope.$digest).toThrow();
+ jqLite(document.body).html('');
+ }));
+
it('should remove previously included text if a falsy value is bound to src', inject(
putIntoCache('myUrl', '{{name}}'),
function($rootScope, $compile) {
@@ -308,7 +352,7 @@ describe('ngInclude ngAnimate', function() {
}
function applyCSS(element, cssProp, cssValue) {
- element.css(cssProp, cssValue);
+ element.css(cssProp, cssValue);
element.css(vendorPrefix + cssProp, cssValue);
}
diff --git a/test/ng/directive/ngSrcSpec.js b/test/ng/directive/ngSrcSpec.js
index a917c511..23ace7ee 100644
--- a/test/ng/directive/ngSrcSpec.js
+++ b/test/ng/directive/ngSrcSpec.js
@@ -14,4 +14,48 @@ describe('ngSrc', function() {
expect(element.attr('src')).not.toBe('');
expect(element.attr('src')).toBe(undefined);
}));
+
+ describe('iframe[ng-src]', function() {
+ it('should pass through src attributes for the same domain', inject(function($compile, $rootScope) {
+ element = $compile('<iframe ng-src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = "different_page";
+ $rootScope.$apply();
+ expect(element.attr('src')).toEqual('different_page');
+ }));
+
+ it('should error on src attributes for a different domain', inject(function($compile, $rootScope) {
+ element = $compile('<iframe ng-src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = "http://a.different.domain.example.com";
+ expect(function() { $rootScope.$apply() }).toThrow(
+ "[$interpolate:interr] Can't interpolate: {{testUrl}}\nError: [$sce:isecrurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: " +
+ "http://a.different.domain.example.com");
+ }));
+
+ it('should error on JS src attributes', inject(function($compile, $rootScope) {
+ element = $compile('<iframe ng-src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = "javascript:alert(1);";
+ expect(function() { $rootScope.$apply() }).toThrow(
+ "[$interpolate:interr] Can't interpolate: {{testUrl}}\nError: [$sce:isecrurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: " +
+ "javascript:alert(1);");
+ }));
+
+ it('should error on non-resource_url src attributes', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<iframe ng-src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()");
+ expect($rootScope.$apply).toThrow(
+ "[$interpolate:interr] Can't interpolate: {{testUrl}}\nError: [$sce:isecrurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: " +
+ "javascript:doTrustedStuff()");
+ }));
+
+ it('should pass through $sce.trustAs() values in src attributes', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<iframe ng-src="{{testUrl}}"></iframe>')($rootScope);
+ $rootScope.testUrl = $sce.trustAsResourceUrl("javascript:doTrustedStuff()");
+ $rootScope.$apply();
+
+ expect(element.attr('src')).toEqual('javascript:doTrustedStuff()');
+ }));
+ });
});
diff --git a/test/ng/interpolateSpec.js b/test/ng/interpolateSpec.js
index 7569c0e2..d74b764a 100644
--- a/test/ng/interpolateSpec.js
+++ b/test/ng/interpolateSpec.js
@@ -67,6 +67,55 @@ describe('$interpolate', function() {
}));
+ describe('interpolating in a trusted context', function() {
+ var sce;
+ beforeEach(function() {
+ function log() {};
+ var fakeLog = {log: log, warn: log, info: log, error: log};
+ module(function($provide, $sceProvider) {
+ $provide.value('$log', fakeLog);
+ $sceProvider.enabled(true);
+ });
+ inject(['$sce', function($sce) { sce = $sce; }]);
+ });
+
+ it('should NOT interpolate non-trusted expressions', inject(function($interpolate) {
+ var foo = "foo";
+ expect($interpolate('{{foo}}', true, sce.CSS)({}, {foo: foo})).toEqual('');
+ }));
+
+ it('should NOT interpolate mistyped expressions', inject(function($interpolate) {
+ var foo = sce.trustAsCss("foo");
+ expect($interpolate('{{foo}}', true, sce.HTML)({}, {foo: foo})).toEqual('');
+ }));
+
+ it('should interpolate trusted expressions in a regular context', inject(function($interpolate) {
+ var foo = sce.trustAsCss("foo");
+ expect($interpolate('{{foo}}', true)({foo: foo})).toEqual('foo');
+ }));
+
+ it('should interpolate trusted expressions in a specific trustedContext', inject(function($interpolate) {
+ var foo = sce.trustAsCss("foo");
+ expect($interpolate('{{foo}}', true, sce.CSS)({foo: foo})).toEqual('foo');
+ }));
+
+ // The concatenation of trusted values does not necessarily result in a trusted value. (For
+ // instance, you can construct evil JS code by putting together pieces of JS strings that are by
+ // themselves safe to execute in isolation.)
+ it('should NOT interpolate trusted expressions with multiple parts', inject(function($interpolate) {
+ var foo = sce.trustAsCss("foo");
+ var bar = sce.trustAsCss("bar");
+ expect(function() {
+ return $interpolate('{{foo}}{{bar}}', true, sce.CSS)(
+ {foo: foo, bar: bar}); }).toThrow(
+ "[$interpolate:noconcat] Error while interpolating: {{foo}}{{bar}}\n" +
+ "Strict Contextual Escaping disallows interpolations that concatenate multiple " +
+ "expressions when a trusted value is required. See " +
+ "http://docs.angularjs.org/api/ng.$sce");
+ }));
+ });
+
+
describe('provider', function() {
beforeEach(module(function($interpolateProvider) {
$interpolateProvider.startSymbol('--');
@@ -155,13 +204,15 @@ describe('$interpolate', function() {
expect(function() {
$interpolate('constant/{{var}}', true, isTrustedContext);
}).toThrow(
- "[$interpolate:noconcat] Error while interpolating: constant/{{var}}\nYou may not use " +
- "multiple expressions when interpolating this expression.");
+ "[$interpolate:noconcat] Error while interpolating: constant/{{var}}\nStrict " +
+ "Contextual Escaping disallows interpolations that concatenate multiple expressions " +
+ "when a trusted value is required. See http://docs.angularjs.org/api/ng.$sce");
expect(function() {
$interpolate('{{foo}}{{bar}}', true, isTrustedContext);
}).toThrow(
- "[$interpolate:noconcat] Error while interpolating: {{foo}}{{bar}}\nYou may not use " +
- "multiple expressions when interpolating this expression.");
+ "[$interpolate:noconcat] Error while interpolating: {{foo}}{{bar}}\nStrict " +
+ "Contextual Escaping disallows interpolations that concatenate multiple expressions " +
+ "when a trusted value is required. See http://docs.angularjs.org/api/ng.$sce");
}));
it('should interpolate a multi-part expression when isTrustedContext is false', inject(function($interpolate) {
diff --git a/test/ng/sceSpecs.js b/test/ng/sceSpecs.js
new file mode 100644
index 00000000..16525b8d
--- /dev/null
+++ b/test/ng/sceSpecs.js
@@ -0,0 +1,347 @@
+'use strict';
+
+describe('SCE', function() {
+
+ describe('when disabled', function() {
+ beforeEach(function() {
+ module(function($sceProvider) {
+ $sceProvider.enabled(false);
+ });
+ });
+
+ it('should provide the getter for enabled', inject(function($sce) {
+ expect($sce.isEnabled()).toBe(false);
+ }));
+
+ it('should not wrap/unwrap any value or throw exception on non-string values', inject(function($sce) {
+ var originalValue = { foo: "bar" };
+ expect($sce.trustAs($sce.JS, originalValue)).toBe(originalValue);
+ expect($sce.getTrusted($sce.JS, originalValue)).toBe(originalValue);
+ }));
+ });
+
+ describe('IE8 quirks mode', function() {
+ function runTest(enabled, documentMode, expectException) {
+ module(function($provide) {
+ $provide.value('$document', [{
+ documentMode: documentMode,
+ createElement: function() {}
+ }]);
+ $provide.value('$sceDelegate', {trustAs: null, valueOf: null, getTrusted: null});
+ });
+
+ inject(function($window, $injector) {
+ function constructSce() {
+ var sceProvider = new $SceProvider();
+ sceProvider.enabled(enabled);
+ return $injector.invoke(sceProvider.$get, sceProvider);
+ }
+
+ var origMsie = $window.msie;
+ try {
+ $window.msie = true;
+ if (expectException) {
+ expect(constructSce).toThrow(
+ '[$sce:iequirks] Strict Contextual Escaping does not support Internet Explorer ' +
+ 'version < 9 in quirks mode. You can fix this by adding the text <!doctype html> to ' +
+ 'the top of your HTML document. See http://docs.angularjs.org/api/ng.$sce for more ' +
+ 'information.');
+ } else {
+ // no exception.
+ constructSce();
+ }
+ }
+ finally {
+ $window.msie = origMsie;
+ }
+ });
+ }
+
+ it('should throw an exception when sce is enabled in quirks mode', function() {
+ runTest(true, 7, true);
+ });
+
+ it('should NOT throw an exception when sce is enabled and in standards mode', function() {
+ runTest(true, 8, false);
+ });
+
+ it('should NOT throw an exception when sce is enabled and documentMode is undefined', function() {
+ runTest(true, undefined, false);
+ });
+
+ it('should NOT throw an exception when sce is disabled even when in quirks mode', function() {
+ runTest(false, 7, false);
+ });
+
+ it('should NOT throw an exception when sce is disabled and in standards mode', function() {
+ runTest(false, 8, false);
+ });
+
+ it('should NOT throw an exception when sce is disabled and documentMode is undefined', function() {
+ runTest(false, undefined, false);
+ });
+ });
+
+ describe('when enabled', function() {
+ it('should wrap string values with TrustedValueHolder', inject(function($sce) {
+ var originalValue = 'original_value';
+ var wrappedValue = $sce.trustAs($sce.HTML, originalValue);
+ expect(typeof wrappedValue).toBe('object');
+ expect($sce.getTrusted($sce.HTML, wrappedValue)).toBe('original_value');
+ expect(function() { $sce.getTrusted($sce.CSS, wrappedValue); }).toThrow(
+ '[$sce:unsafe] Attempting to use an unsafe value in a safe context.');
+ wrappedValue = $sce.trustAs($sce.CSS, originalValue);
+ expect(typeof wrappedValue).toBe('object');
+ expect($sce.getTrusted($sce.CSS, wrappedValue)).toBe('original_value');
+ expect(function() { $sce.getTrusted($sce.HTML, wrappedValue); }).toThrow(
+ '[$sce:unsafe] Attempting to use an unsafe value in a safe context.');
+ wrappedValue = $sce.trustAs($sce.URL, originalValue);
+ expect(typeof wrappedValue).toBe('object');
+ expect($sce.getTrusted($sce.URL, wrappedValue)).toBe('original_value');
+ wrappedValue = $sce.trustAs($sce.JS, originalValue);
+ expect(typeof wrappedValue).toBe('object');
+ expect($sce.getTrusted($sce.JS, wrappedValue)).toBe('original_value');
+ }));
+
+ it('should NOT wrap non-string values', inject(function($sce) {
+ expect(function() { $sce.trustAsCss(123); }).toThrow(
+ '[$sce:itype] Attempted to trust a non-string value in a content requiring a string: ' +
+ 'Context: css');
+ }));
+
+ it('should NOT wrap unknown contexts', inject(function($sce) {
+ expect(function() { $sce.trustAs('unknown1' , '123'); }).toThrow(
+ '[$sce:icontext] Attempted to trust a value in invalid context. Context: unknown1; Value: 123');
+ }));
+
+ it('should NOT wrap undefined context', inject(function($sce) {
+ expect(function() { $sce.trustAs(undefined, '123'); }).toThrow(
+ '[$sce:icontext] Attempted to trust a value in invalid context. Context: undefined; Value: 123');
+ }));
+
+ it('should wrap undefined into undefined', inject(function($sce) {
+ expect($sce.trustAsHtml(undefined)).toBe(undefined);
+ }));
+
+ it('should unwrap undefined into undefined', inject(function($sce) {
+ expect($sce.getTrusted($sce.HTML, undefined)).toBe(undefined);
+ }));
+
+ it('should wrap null into null', inject(function($sce) {
+ expect($sce.trustAsHtml(null)).toBe(null);
+ }));
+
+ it('should unwrap null into null', inject(function($sce) {
+ expect($sce.getTrusted($sce.HTML, null)).toBe(null);
+ }));
+
+ it('should wrap "" into ""', inject(function($sce) {
+ expect($sce.trustAsHtml("")).toBe("");
+ }));
+
+ it('should unwrap null into null', inject(function($sce) {
+ expect($sce.getTrusted($sce.HTML, null)).toBe(null);
+ }));
+
+ it('should unwrap "" into ""', inject(function($sce) {
+ expect($sce.getTrusted($sce.HTML, "")).toBe("");
+ }));
+
+ it('should unwrap values and return the original', inject(function($sce) {
+ var originalValue = "originalValue";
+ var wrappedValue = $sce.trustAs($sce.HTML, originalValue);
+ expect($sce.getTrusted($sce.HTML, wrappedValue)).toBe(originalValue);
+ }));
+
+ it('should NOT unwrap values when the type is different', inject(function($sce) {
+ var originalValue = "originalValue";
+ var wrappedValue = $sce.trustAs($sce.HTML, originalValue);
+ expect(function () { $sce.getTrusted($sce.CSS, wrappedValue); }).toThrow(
+ '[$sce:unsafe] Attempting to use an unsafe value in a safe context.');
+ }));
+
+ it('should NOT unwrap values that had not been wrapped', inject(function($sce) {
+ function TrustedValueHolder(trustedValue) {
+ this.$unwrapTrustedValue = function() {
+ return trustedValue;
+ };
+ }
+ var wrappedValue = new TrustedValueHolder("originalValue");
+ expect(function() { return $sce.getTrusted($sce.HTML, wrappedValue) }).toThrow(
+ '[$sce:unsafe] Attempting to use an unsafe value in a safe context.');
+ }));
+
+ it('should implement toString on trusted values', inject(function($sce) {
+ var originalValue = '123',
+ wrappedValue = $sce.trustAsHtml(originalValue);
+ expect($sce.getTrustedHtml(wrappedValue)).toBe(originalValue);
+ expect(wrappedValue.toString()).toBe(originalValue.toString());
+ }));
+ });
+
+
+ describe('replace $sceDelegate', function() {
+ it('should override the default $sce.trustAs/valueOf/etc.', function() {
+ module(function($provide) {
+ $provide.value('$sceDelegate', {
+ trustAs: function(type, value) { return "wrapped:" + value; },
+ getTrusted: function(type, value) { return "unwrapped:" + value; },
+ valueOf: function(value) { return "valueOf:" + value; }
+ });
+ });
+
+ inject(function($sce) {
+ expect($sce.trustAsJs("value")).toBe("wrapped:value");
+ expect($sce.valueOf("value")).toBe("valueOf:value");
+ expect($sce.getTrustedJs("value")).toBe("unwrapped:value");
+ expect($sce.parseAsJs("name")({name: "chirayu"})).toBe("unwrapped:chirayu");
+ });
+ });
+ });
+
+
+ describe('$sce.parseAs', function($sce) {
+ it('should parse constant literals as trusted', inject(function($sce) {
+ expect($sce.parseAsJs('1')()).toBe(1);
+ expect($sce.parseAsJs('1', $sce.ANY)()).toBe(1);
+ expect($sce.parseAsJs('1', $sce.HTML)()).toBe(1);
+ expect($sce.parseAsJs('1', 'UNDEFINED')()).toBe(1);
+ expect($sce.parseAsJs('true')()).toBe(true);
+ expect($sce.parseAsJs('false')()).toBe(false);
+ expect($sce.parseAsJs('null')()).toBe(null);
+ expect($sce.parseAsJs('undefined')()).toBe(undefined);
+ expect($sce.parseAsJs('"string"')()).toBe("string");
+ }));
+
+ it('should NOT parse constant non-literals', inject(function($sce) {
+ // Until there's a real world use case for this, we're disallowing
+ // constant non-literals. See $SceParseProvider.
+ var exprFn = $sce.parseAsJs('1+1');
+ expect(exprFn).toThrow();
+ }));
+
+ it('should NOT return untrusted values from expression function', inject(function($sce) {
+ var exprFn = $sce.parseAs($sce.HTML, 'foo');
+ expect(function() {
+ return exprFn({}, {'foo': true})
+ }).toThrow(
+ '[$sce:unsafe] Attempting to use an unsafe value in a safe context.');
+ }));
+
+ it('should NOT return trusted values of the wrong type from expression function', inject(function($sce) {
+ var exprFn = $sce.parseAs($sce.HTML, 'foo');
+ expect(function() {
+ return exprFn({}, {'foo': $sce.trustAs($sce.JS, '123')})
+ }).toThrow(
+ '[$sce:unsafe] Attempting to use an unsafe value in a safe context.');
+ }));
+
+ it('should return trusted values from expression function', inject(function($sce) {
+ var exprFn = $sce.parseAs($sce.HTML, 'foo');
+ expect(exprFn({}, {'foo': $sce.trustAs($sce.HTML, 'trustedValue')})).toBe('trustedValue');
+ }));
+
+ it('should support shorthand methods', inject(function($sce) {
+ // Test shorthand parse methods.
+ expect($sce.parseAsHtml('1')()).toBe(1);
+ // Test short trustAs methods.
+ expect($sce.trustAsAny).toBeUndefined();
+ expect(function() {
+ // mismatched types.
+ $sce.parseAsCss('foo')({}, {'foo': $sce.trustAsHtml('1')});
+ }).toThrow(
+ '[$sce:unsafe] Attempting to use an unsafe value in a safe context.');
+ }));
+
+ });
+
+ describe('$sceDelegate resource url policies', function() {
+ function runTest(cfg, testFn) {
+ return function() {
+ module(function($sceDelegateProvider) {
+ if (cfg.whiteList !== undefined) {
+ $sceDelegateProvider.resourceUrlWhitelist(cfg.whiteList);
+ }
+ if (cfg.blackList !== undefined) {
+ $sceDelegateProvider.resourceUrlBlacklist(cfg.blackList);
+ }
+ });
+ inject(testFn);
+ }
+ }
+
+ it('should default to "self" which allows relative urls', runTest({}, function($sce, $document) {
+ expect($sce.getTrustedResourceUrl('foo/bar')).toEqual('foo/bar');
+ }));
+
+ it('should reject everything when whitelist is empty', runTest(
+ {
+ whiteList: [],
+ blackList: []
+ }, function($sce) {
+ expect(function() { $sce.getTrustedResourceUrl('#'); }).toThrow(
+ '[$sce:isecrurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL: #');
+ }));
+
+ it('should match against normalized urls', runTest(
+ {
+ whiteList: [/^foo$/],
+ blackList: []
+ }, function($sce) {
+ expect(function() { $sce.getTrustedResourceUrl('foo'); }).toThrow(
+ '[$sce:isecrurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL: foo');
+ }));
+
+ it('should support custom regex', runTest(
+ {
+ whiteList: [/^http:\/\/example\.com.*/],
+ blackList: []
+ }, function($sce) {
+ expect($sce.getTrustedResourceUrl('http://example.com/foo')).toEqual('http://example.com/foo');
+ expect(function() { $sce.getTrustedResourceUrl('https://example.com/foo'); }).toThrow(
+ '[$sce:isecrurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL: https://example.com/foo');
+ }));
+
+ it('should support the special string "self" in whitelist', runTest(
+ {
+ whiteList: ['self'],
+ blackList: []
+ }, function($sce) {
+ expect($sce.getTrustedResourceUrl('foo')).toEqual('foo');
+ }));
+
+ it('should support the special string "self" in blacklist', runTest(
+ {
+ whiteList: [/.*/],
+ blackList: ['self']
+ }, function($sce) {
+ expect(function() { $sce.getTrustedResourceUrl('foo'); }).toThrow(
+ '[$sce:isecrurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL: foo');
+ }));
+
+ it('should have blacklist override the whitelist', runTest(
+ {
+ whiteList: ['self'],
+ blackList: ['self']
+ }, function($sce) {
+ expect(function() { $sce.getTrustedResourceUrl('foo'); }).toThrow(
+ '[$sce:isecrurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL: foo');
+ }));
+
+ it('should support multiple items in both lists', runTest(
+ {
+ whiteList: [/^http:\/\/example.com\/1$/, /^http:\/\/example.com\/2$/, /^http:\/\/example.com\/3$/, 'self'],
+ blackList: [/^http:\/\/example.com\/3$/, /open_redirect/],
+ }, function($sce) {
+ expect($sce.getTrustedResourceUrl('same_domain')).toEqual('same_domain');
+ expect($sce.getTrustedResourceUrl('http://example.com/1')).toEqual('http://example.com/1');
+ expect($sce.getTrustedResourceUrl('http://example.com/2')).toEqual('http://example.com/2');
+ expect(function() { $sce.getTrustedResourceUrl('http://example.com/3'); }).toThrow(
+ '[$sce:isecrurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL: http://example.com/3');
+ expect(function() { $sce.getTrustedResourceUrl('open_redirect'); }).toThrow(
+ '[$sce:isecrurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL: open_redirect');
+ }));
+
+ });
+});
+
diff --git a/test/ng/urlUtilsSpec.js b/test/ng/urlUtilsSpec.js
index 57043a5a..3c9bf847 100644
--- a/test/ng/urlUtilsSpec.js
+++ b/test/ng/urlUtilsSpec.js
@@ -11,21 +11,27 @@ describe('$$urlUtils', function() {
expect(parsed.href).toMatch(/https?:\/\//);
expect(parsed.protocol).toMatch(/^https?:/);
expect(parsed.host).not.toBe("");
+ expect(parsed.hostname).not.toBe("");
+ expect(parsed.pathname).not.toBe("");
}));
});
describe('isSameOrigin', function() {
- it('should support various combinations of urls', inject(function($$urlUtils, $document) {
- expect($$urlUtils.isSameOrigin('path')).toBe(true);
+ it('should support various combinations of urls - both string and parsed', inject(function($$urlUtils, $document) {
+ function expectIsSameOrigin(url, expectedValue) {
+ expect($$urlUtils.isSameOrigin(url)).toBe(expectedValue);
+ expect($$urlUtils.isSameOrigin($$urlUtils.resolve(url, true))).toBe(expectedValue);
+ }
+ expectIsSameOrigin('path', true);
var origin = $$urlUtils.resolve($document[0].location.href, true);
- expect($$urlUtils.isSameOrigin('//' + origin.host + '/path')).toBe(true);
+ expectIsSameOrigin('//' + origin.host + '/path', true);
// Different domain.
- expect($$urlUtils.isSameOrigin('http://example.com/path')).toBe(false);
+ expectIsSameOrigin('http://example.com/path', false);
// Auto fill protocol.
- expect($$urlUtils.isSameOrigin('//example.com/path')).toBe(false);
+ expectIsSameOrigin('//example.com/path', false);
// Should not match when the ports are different.
// This assumes that the test is *not* running on port 22 (very unlikely).
- expect($$urlUtils.isSameOrigin('//' + origin.hostname + ':22/path')).toBe(false);
+ expectIsSameOrigin('//' + origin.hostname + ':22/path', false);
}));
});
});
diff --git a/test/ngRoute/routeSpec.js b/test/ngRoute/routeSpec.js
index 300ca2d7..13d149a1 100644
--- a/test/ngRoute/routeSpec.js
+++ b/test/ngRoute/routeSpec.js
@@ -13,6 +13,7 @@ describe('$route', function() {
$httpBackend.when('GET', 'foo.html').respond('foo');
$httpBackend.when('GET', 'baz.html').respond('baz');
$httpBackend.when('GET', 'bar.html').respond('bar');
+ $httpBackend.when('GET', 'http://example.com/trusted-template.html').respond('cross domain trusted template');
$httpBackend.when('GET', '404.html').respond('not found');
};
}));
@@ -510,6 +511,33 @@ describe('$route', function() {
});
});
+ it('should NOT load cross domain templates by default', function() {
+ module(function($routeProvider) {
+ $routeProvider.when('/foo', { templateUrl: 'http://example.com/foo.html' });
+ });
+
+ inject(function ($route, $location, $rootScope) {
+ $location.path('/foo');
+ expect(function() {
+ $rootScope.$digest();
+ }).toThrow('[$sce:isecrurl] Blocked loading resource from url not allowed by $sceDelegate policy. URL: http://example.com/foo.html');
+ });
+ });
+
+ it('should load cross domain templates that are trusted', function() {
+ module(function($routeProvider, $sceDelegateProvider) {
+ $routeProvider.when('/foo', { templateUrl: 'http://example.com/foo.html' });
+ $sceDelegateProvider.resourceUrlWhitelist([/^http:\/\/example\.com\/foo\.html$/]);
+ });
+
+ inject(function ($route, $location, $rootScope) {
+ $httpBackend.whenGET('http://example.com/foo.html').respond('FOO BODY');
+ $location.path('/foo');
+ $rootScope.$digest();
+ $httpBackend.flush();
+ expect($route.current.locals.$template).toEqual('FOO BODY');
+ });
+ });
it('should not update $routeParams until $routeChangeSuccess', function() {
module(function($routeProvider) {
@@ -904,7 +932,7 @@ describe('$route', function() {
return '<h1>' + routePathParams.id + '</h1>';
}
- module(function($routeProvider){
+ module(function($routeProvider) {
$routeProvider.when('/bar/:id/:subid/:subsubid', {templateUrl: 'bar.html'});
$routeProvider.when('/foo/:id', {template: customTemplateFn});
});
diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js
index 5fae2817..d97d88a1 100644
--- a/test/testabilityPatch.js
+++ b/test/testabilityPatch.js
@@ -107,7 +107,12 @@ function dealoc(obj) {
function cleanup(element) {
element.off().removeData();
- for ( var i = 0, children = element.contents() || []; i < children.length; i++) {
+ // 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]));
}
}