')($rootScope);
expect(attrs.title).toBeUndefined();
expect(attrs.$attr.title).toBeUndefined();
expect(attrs.ngPropTitle).toBe('12');
expect(attrs.$attr.ngPropTitle).toBe('ng-prop-title');
expect(attrs.superTitle).toBeUndefined();
expect(attrs.$attr.superTitle).toBeUndefined();
expect(attrs.ngPropSuperTitle).toBe('34');
expect(attrs.$attr.ngPropSuperTitle).toBe('ng-prop-super-title');
expect(attrs.myCamelTitle).toBeUndefined();
expect(attrs.$attr.myCamelTitle).toBeUndefined();
expect(attrs.ngPropMyCamelTitle).toBe('56');
expect(attrs.$attr.ngPropMyCamelTitle).toBe('ng-prop-my-camel_title');
});
});
it('should not conflict with (ng-attr-)attribute mappings of the same name', function() {
var attrs;
module(function($compileProvider) {
$compileProvider.directive('attrExposer', valueFn({
link: function($scope, $element, $attrs) {
attrs = $attrs;
}
}));
});
inject(function($compile, $rootScope) {
$compile('
')($rootScope);
expect(attrs.title).toBe('foo');
expect(attrs.$attr.title).toBe('title');
expect(attrs.$attr.ngPropTitle).toBe('ng-prop-title');
});
});
it('should disallow property binding to onclick', inject(function($compile, $rootScope) {
// All event prop bindings are disallowed.
expect(function() {
$compile('
');
}).toThrowMinErr(
'$compile', 'nodomevents', 'Property bindings for HTML DOM event properties are disallowed');
expect(function() {
$compile('
');
}).toThrowMinErr(
'$compile', 'nodomevents', 'Property bindings for HTML DOM event properties are disallowed');
}));
it('should process property bindings in pre-linking phase at priority 100', function() {
module(provideLog);
module(function($compileProvider) {
$compileProvider.directive('propLog', function(log, $rootScope) {
return {
compile: function($element, $attrs) {
log('compile=' + $element.prop('myName'));
return {
pre: function($scope, $element, $attrs) {
log('preLinkP0=' + $element.prop('myName'));
$rootScope.name = 'pre0';
},
post: function($scope, $element, $attrs) {
log('postLink=' + $element.prop('myName'));
$rootScope.name = 'post0';
}
};
}
};
});
});
module(function($compileProvider) {
$compileProvider.directive('propLogHighPriority', function(log, $rootScope) {
return {
priority: 101,
compile: function() {
return {
pre: function($scope, $element, $attrs) {
log('preLinkP101=' + $element.prop('myName'));
$rootScope.name = 'pre101';
}
};
}
};
});
});
inject(function($rootScope, $compile, log) {
var element = $compile('
')($rootScope);
$rootScope.name = 'angular';
$rootScope.$apply();
log('digest=' + element.prop('myName'));
expect(log).toEqual('compile=undefined; preLinkP101=undefined; preLinkP0=pre101; postLink=pre101; digest=angular');
});
});
['img', 'audio', 'video'].forEach(function(tag) {
// Support: IE 9 only
// IE9 rejects the `video` / `audio` tags with "Error: Not implemented"
if (msie !== 9 || tag === 'img') {
describe(tag + '[src] context requirement', function() {
it('should NOT require trusted values for trusted URIs', inject(function($rootScope, $compile) {
var element = $compile('<' + tag + ' ng-prop-src="testUrl">' + tag + '>')($rootScope);
$rootScope.testUrl = 'http://example.com/image.mp4'; // `http` is trusted
$rootScope.$digest();
expect(element.prop('src')).toEqual('http://example.com/image.mp4');
}));
it('should accept trusted values', inject(function($rootScope, $compile, $sce) {
// As a MEDIA_URL URL
var element = $compile('<' + tag + ' ng-prop-src="testUrl">' + tag + '>')($rootScope);
// Some browsers complain if you try to write `javascript:` into an `img[src]`
// So for the test use something different
$rootScope.testUrl = $sce.trustAsMediaUrl('untrusted:foo()');
$rootScope.$digest();
expect(element.prop('src')).toEqual('untrusted:foo()');
// As a URL
element = $compile('<' + tag + ' ng-prop-src="testUrl">' + tag + '>')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl('untrusted:foo()');
$rootScope.$digest();
expect(element.prop('src')).toEqual('untrusted:foo()');
// As a RESOURCE URL
element = $compile('<' + tag + ' ng-prop-src="testUrl">' + tag + '>')($rootScope);
$rootScope.testUrl = $sce.trustAsResourceUrl('untrusted:foo()');
$rootScope.$digest();
expect(element.prop('src')).toEqual('untrusted:foo()');
}));
it('should sanitize non-trusted values', inject(function($rootScope, $compile, $sce) {
// As a MEDIA_URL URL
var element = $compile('<' + tag + ' ng-prop-src="testUrl">' + tag + '>')($rootScope);
// Some browsers complain if you try to write `javascript:` into an `img[src]`
// So for the test use something different
$rootScope.testUrl = 'untrusted:foo()';
$rootScope.$digest();
expect(element.prop('src')).toEqual('unsafe:untrusted:foo()');
}));
it('should sanitize wrongly typed values', inject(function($rootScope, $compile, $sce) {
// As a MEDIA_URL URL
var element = $compile('<' + tag + ' ng-prop-src="testUrl">' + tag + '>')($rootScope);
// Some browsers complain if you try to write `javascript:` into an `img[src]`
// So for the test use something different
$rootScope.testUrl = $sce.trustAsCss('untrusted:foo()');
$rootScope.$digest();
expect(element.prop('src')).toEqual('unsafe:untrusted:foo()');
}));
});
}
});
// Support: IE 9 only
// IE 9 rejects the `source` / `track` tags with
// "Unable to get value of the property 'childNodes': object is null or undefined"
if (msie !== 9) {
['source', 'track'].forEach(function(tag) {
describe(tag + '[src]', function() {
it('should NOT require trusted values for trusted URIs', inject(function($rootScope, $compile) {
var element = $compile('
<' + tag + ' ng-prop-src="testUrl">' + tag + '> ')($rootScope);
$rootScope.testUrl = 'http://example.com/image.mp4'; // `http` is trusted
$rootScope.$digest();
expect(element.find(tag).prop('src')).toEqual('http://example.com/image.mp4');
}));
it('should accept trusted values', inject(function($rootScope, $compile, $sce) {
// As a MEDIA_URL URL
var element = $compile('
<' + tag + ' ng-prop-src="testUrl">' + tag + '> ')($rootScope);
$rootScope.testUrl = $sce.trustAsMediaUrl('javascript:foo()');
$rootScope.$digest();
expect(element.find(tag).prop('src')).toEqual('javascript:foo()');
// As a URL
element = $compile('
<' + tag + ' ng-prop-src="testUrl">' + tag + '> ')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl('javascript:foo()');
$rootScope.$digest();
expect(element.find(tag).prop('src')).toEqual('javascript:foo()');
// As a RESOURCE URL
element = $compile('
<' + tag + ' ng-prop-src="testUrl">' + tag + '> ')($rootScope);
$rootScope.testUrl = $sce.trustAsResourceUrl('javascript:foo()');
$rootScope.$digest();
expect(element.find(tag).prop('src')).toEqual('javascript:foo()');
}));
it('should sanitize non-trusted values', inject(function($rootScope, $compile, $sce) {
var element = $compile('
<' + tag + ' ng-prop-src="testUrl">' + tag + '> ')($rootScope);
$rootScope.testUrl = 'untrusted:foo()';
$rootScope.$digest();
expect(element.find(tag).prop('src')).toEqual('unsafe:untrusted:foo()');
}));
it('should sanitize wrongly typed values', inject(function($rootScope, $compile, $sce) {
var element = $compile('
<' + tag + ' ng-prop-src="testUrl">' + tag + '> ')($rootScope);
$rootScope.testUrl = $sce.trustAsCss('untrusted:foo()');
$rootScope.$digest();
expect(element.find(tag).prop('src')).toEqual('unsafe:untrusted:foo()');
}));
});
});
}
describe('img[src] sanitization', function() {
it('should accept trusted values', inject(function($rootScope, $compile, $sce) {
var element = $compile('
')($rootScope);
// Some browsers complain if you try to write `javascript:` into an `img[src]`
// So for the test use something different
$rootScope.testUrl = $sce.trustAsMediaUrl('someuntrustedthing:foo();');
$rootScope.$digest();
expect(element.prop('src')).toEqual('someuntrustedthing:foo();');
}));
it('should use $$sanitizeUri', function() {
var $$sanitizeUri = jasmine.createSpy('$$sanitizeUri').and.returnValue('someSanitizedUrl');
module(function($provide) {
$provide.value('$$sanitizeUri', $$sanitizeUri);
});
inject(function($compile, $rootScope) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'someUrl';
$rootScope.$apply();
expect(element.prop('src')).toMatch(/^http:\/\/.*\/someSanitizedUrl$/);
expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, true);
});
});
it('should not use $$sanitizeUri with trusted values', function() {
var $$sanitizeUri = jasmine.createSpy('$$sanitizeUri').and.throwError('Should not have been called');
module(function($provide) {
$provide.value('$$sanitizeUri', $$sanitizeUri);
});
inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
// Assigning javascript:foo to src makes at least IE9-11 complain, so use another
// protocol name.
$rootScope.testUrl = $sce.trustAsMediaUrl('untrusted:foo();');
$rootScope.$apply();
expect(element.prop('src')).toBe('untrusted:foo();');
});
});
});
['img', 'source'].forEach(function(srcsetElement) {
// Support: IE 9 only
// IE9 ignores source[srcset] property assignments
if (msie !== 9 || srcsetElement === 'img') {
describe(srcsetElement + '[srcset] sanitization', function() {
it('should not error if srcset is blank', inject(function($compile, $rootScope) {
var element = $compile('<' + srcsetElement + ' ng-prop-srcset="testUrl">' + srcsetElement + '>')($rootScope);
// Set srcset to a value
$rootScope.testUrl = 'http://example.com/';
$rootScope.$digest();
expect(element.prop('srcset')).toBe('http://example.com/');
// Now set it to blank
$rootScope.testUrl = '';
$rootScope.$digest();
expect(element.prop('srcset')).toBe('');
}));
it('should NOT require trusted values for trusted URI values', inject(function($rootScope, $compile, $sce) {
var element = $compile('<' + srcsetElement + ' ng-prop-srcset="testUrl">' + srcsetElement + '>')($rootScope);
$rootScope.testUrl = 'http://example.com/image.png'; // `http` is trusted
$rootScope.$digest();
expect(element.prop('srcset')).toEqual('http://example.com/image.png');
}));
it('should accept trusted values, if they are also trusted URIs', inject(function($rootScope, $compile, $sce) {
var element = $compile('<' + srcsetElement + ' ng-prop-srcset="testUrl">' + srcsetElement + '>')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl('http://example.com');
$rootScope.$digest();
expect(element.prop('srcset')).toEqual('http://example.com');
}));
it('should NOT work with trusted values', inject(function($rootScope, $compile, $sce) {
// A limitation of the approach used for srcset is that you cannot use `trustAsUrl`.
// Use trustAsHtml and ng-bind-html to work around this.
var element = $compile('<' + srcsetElement + ' ng-prop-srcset="testUrl">' + srcsetElement + '>')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl('javascript:something');
$rootScope.$digest();
expect(element.prop('srcset')).toEqual('unsafe:javascript:something');
element = $compile('<' + srcsetElement + ' ng-prop-srcset="testUrl + \',\' + testUrl">' + srcsetElement + '>')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl('javascript:something');
$rootScope.$digest();
expect(element.prop('srcset')).toEqual(
'unsafe:javascript:something ,unsafe:javascript:something');
}));
it('should use $$sanitizeUri', function() {
var $$sanitizeUri = jasmine.createSpy('$$sanitizeUri').and.returnValue('someSanitizedUrl');
module(function($provide) {
$provide.value('$$sanitizeUri', $$sanitizeUri);
});
inject(function($compile, $rootScope) {
var element = $compile('<' + srcsetElement + ' ng-prop-srcset="testUrl">' + srcsetElement + '>')($rootScope);
$rootScope.testUrl = 'someUrl';
$rootScope.$apply();
expect(element.prop('srcset')).toBe('someSanitizedUrl');
expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, true);
element = $compile('<' + srcsetElement + ' ng-prop-srcset="testUrl + \',\' + testUrl">' + srcsetElement + '>')($rootScope);
$rootScope.testUrl = 'javascript:yay';
$rootScope.$apply();
expect(element.prop('srcset')).toEqual('someSanitizedUrl ,someSanitizedUrl');
element = $compile('<' + srcsetElement + ' ng-prop-srcset="\'java\' + testUrl">' + srcsetElement + '>')($rootScope);
$rootScope.testUrl = 'script:yay, javascript:nay';
$rootScope.$apply();
expect(element.prop('srcset')).toEqual('someSanitizedUrl ,someSanitizedUrl');
});
});
it('should sanitize all uris in srcset', inject(function($rootScope, $compile) {
var element = $compile('<' + srcsetElement + ' ng-prop-srcset="testUrl">' + srcsetElement + '>')($rootScope);
var testSet = {
'http://example.com/image.png':'http://example.com/image.png',
' http://example.com/image.png':'http://example.com/image.png',
'http://example.com/image.png ':'http://example.com/image.png',
'http://example.com/image.png 128w':'http://example.com/image.png 128w',
'http://example.com/image.png 2x':'http://example.com/image.png 2x',
'http://example.com/image.png 1.5x':'http://example.com/image.png 1.5x',
'http://example.com/image1.png 1x,http://example.com/image2.png 2x':'http://example.com/image1.png 1x,http://example.com/image2.png 2x',
'http://example.com/image1.png 1x ,http://example.com/image2.png 2x':'http://example.com/image1.png 1x ,http://example.com/image2.png 2x',
'http://example.com/image1.png 1x, http://example.com/image2.png 2x':'http://example.com/image1.png 1x,http://example.com/image2.png 2x',
'http://example.com/image1.png 1x , http://example.com/image2.png 2x':'http://example.com/image1.png 1x ,http://example.com/image2.png 2x',
'http://example.com/image1.png 48w,http://example.com/image2.png 64w':'http://example.com/image1.png 48w,http://example.com/image2.png 64w',
//Test regex to make sure doesn't mistake parts of url for width descriptors
'http://example.com/image1.png?w=48w,http://example.com/image2.png 64w':'http://example.com/image1.png?w=48w,http://example.com/image2.png 64w',
'http://example.com/image1.png 1x,http://example.com/image2.png 64w':'http://example.com/image1.png 1x,http://example.com/image2.png 64w',
'http://example.com/image1.png,http://example.com/image2.png':'http://example.com/image1.png ,http://example.com/image2.png',
'http://example.com/image1.png ,http://example.com/image2.png':'http://example.com/image1.png ,http://example.com/image2.png',
'http://example.com/image1.png, http://example.com/image2.png':'http://example.com/image1.png ,http://example.com/image2.png',
'http://example.com/image1.png , http://example.com/image2.png':'http://example.com/image1.png ,http://example.com/image2.png',
'http://example.com/image1.png 1x, http://example.com/image2.png 2x, http://example.com/image3.png 3x':
'http://example.com/image1.png 1x,http://example.com/image2.png 2x,http://example.com/image3.png 3x',
'javascript:doEvilStuff() 2x': 'unsafe:javascript:doEvilStuff() 2x',
'http://example.com/image1.png 1x,javascript:doEvilStuff() 2x':'http://example.com/image1.png 1x,unsafe:javascript:doEvilStuff() 2x',
'http://example.com/image1.jpg?x=a,b 1x,http://example.com/ima,ge2.jpg 2x':'http://example.com/image1.jpg?x=a,b 1x,http://example.com/ima,ge2.jpg 2x',
//Test regex to make sure doesn't mistake parts of url for pixel density descriptors
'http://example.com/image1.jpg?x=a2x,b 1x,http://example.com/ima,ge2.jpg 2x':'http://example.com/image1.jpg?x=a2x,b 1x,http://example.com/ima,ge2.jpg 2x'
};
forEach(testSet, function(ref, url) {
$rootScope.testUrl = url;
$rootScope.$digest();
expect(element.prop('srcset')).toEqual(ref);
});
}));
});
}
});
describe('a[href] sanitization', function() {
it('should NOT require trusted values for trusted URI values', inject(function($rootScope, $compile) {
$rootScope.testUrl = 'http://example.com/image.png'; // `http` is trusted
var element = $compile('
')($rootScope);
$rootScope.$digest();
expect(element.prop('href')).toEqual('http://example.com/image.png');
element = $compile('
')($rootScope);
$rootScope.$digest();
expect(element.prop('href')).toEqual('http://example.com/image.png');
}));
it('should accept trusted values for non-trusted URI values', inject(function($rootScope, $compile, $sce) {
$rootScope.testUrl = $sce.trustAsUrl('javascript:foo()'); // `javascript` is not trusted
var element = $compile('
')($rootScope);
$rootScope.$digest();
expect(element.prop('href')).toEqual('javascript:foo()');
element = $compile('
')($rootScope);
$rootScope.$digest();
expect(element.prop('href')).toEqual('javascript:foo()');
}));
it('should sanitize non-trusted values', inject(function($rootScope, $compile) {
$rootScope.testUrl = 'javascript:foo()'; // `javascript` is not trusted
var element = $compile('
')($rootScope);
$rootScope.$digest();
expect(element.prop('href')).toEqual('unsafe:javascript:foo()');
element = $compile('
')($rootScope);
$rootScope.$digest();
expect(element.prop('href')).toEqual('unsafe:javascript:foo()');
}));
it('should not sanitize href on elements other than anchor', inject(function($compile, $rootScope) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'javascript:doEvilStuff()';
$rootScope.$apply();
expect(element.prop('href')).toBe('javascript:doEvilStuff()');
}));
it('should not sanitize properties other then those configured', inject(function($compile, $rootScope) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'javascript:doEvilStuff()';
$rootScope.$apply();
expect(element.prop('title')).toBe('javascript:doEvilStuff()');
}));
it('should use $$sanitizeUri', function() {
var $$sanitizeUri = jasmine.createSpy('$$sanitizeUri').and.returnValue('someSanitizedUrl');
module(function($provide) {
$provide.value('$$sanitizeUri', $$sanitizeUri);
});
inject(function($compile, $rootScope) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'someUrl';
$rootScope.$apply();
expect(element.prop('href')).toMatch(/^http:\/\/.*\/someSanitizedUrl$/);
expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false);
$$sanitizeUri.calls.reset();
element = $compile('
')($rootScope);
$rootScope.$apply();
expect(element.prop('href')).toMatch(/^http:\/\/.*\/someSanitizedUrl$/);
expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false);
});
});
it('should not have endless digests when given arrays in concatenable context', inject(function($compile, $rootScope) {
var element = $compile('
' +
'
')($rootScope);
$rootScope.testUrl = [1];
$rootScope.$digest();
$rootScope.testUrl = [];
$rootScope.$digest();
$rootScope.testUrl = {a:'b'};
$rootScope.$digest();
$rootScope.testUrl = {};
$rootScope.$digest();
}));
});
describe('iframe[src]', function() {
it('should pass through src properties for the same domain', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'different_page';
$rootScope.$apply();
expect(element.prop('src')).toMatch(/\/different_page$/);
}));
it('should clear out src properties for a different domain', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'http://a.different.domain.example.com';
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
' URL: http://a.different.domain.example.com');
}));
it('should clear out JS src properties', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'javascript:alert(1);';
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
' URL: javascript:alert(1);');
}));
it('should clear out non-resource_url src properties', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl('javascript:doTrustedStuff()');
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
' URL: javascript:doTrustedStuff()');
}));
it('should pass through $sce.trustAs() values in src properties', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = $sce.trustAsResourceUrl('javascript:doTrustedStuff()');
$rootScope.$apply();
expect(element.prop('src')).toEqual('javascript:doTrustedStuff()');
}));
});
describe('base[href]', function() {
it('should be a RESOURCE_URL context', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = $sce.trustAsResourceUrl('https://example.com/');
$rootScope.$apply();
expect(element.prop('href')).toContain('https://example.com/');
$rootScope.testUrl = 'https://not.example.com/';
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
' URL: https://not.example.com/');
}));
});
describe('form[action]', function() {
it('should pass through action property for the same domain', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'different_page';
$rootScope.$apply();
expect(element.prop('action')).toMatch(/\/different_page$/);
}));
it('should clear out action property for a different domain', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'http://a.different.domain.example.com';
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
' URL: http://a.different.domain.example.com');
}));
it('should clear out JS action property', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'javascript:alert(1);';
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
' URL: javascript:alert(1);');
}));
it('should clear out non-resource_url action property', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl('javascript:doTrustedStuff()');
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
' URL: javascript:doTrustedStuff()');
}));
it('should pass through $sce.trustAsResourceUrl() values in action property', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = $sce.trustAsResourceUrl('javascript:doTrustedStuff()');
$rootScope.$apply();
expect(element.prop('action')).toEqual('javascript:doTrustedStuff()');
}));
});
describe('link[href]', function() {
it('should reject invalid RESOURCE_URLs', inject(function($compile, $rootScope) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = 'https://evil.example.org/css.css';
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
' URL: https://evil.example.org/css.css');
}));
it('should accept valid RESOURCE_URLs', inject(function($compile, $rootScope, $sce) {
var element = $compile('
')($rootScope);
$rootScope.testUrl = './css1.css';
$rootScope.$apply();
expect(element.prop('href')).toContain('css1.css');
$rootScope.testUrl = $sce.trustAsResourceUrl('https://elsewhere.example.org/css2.css');
$rootScope.$apply();
expect(element.prop('href')).toContain('https://elsewhere.example.org/css2.css');
}));
});
describe('*[innerHTML]', function() {
describe('SCE disabled', function() {
beforeEach(function() {
module(function($sceProvider) { $sceProvider.enabled(false); });
});
it('should set html', inject(function($rootScope, $compile) {
var element = $compile('
')($rootScope);
$rootScope.html = '
hello
';
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('
hello
');
}));
it('should update html', inject(function($rootScope, $compile, $sce) {
var element = $compile('
')($rootScope);
$rootScope.html = 'hello';
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('hello');
$rootScope.html = 'goodbye';
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('goodbye');
}));
it('should one-time bind if the expression starts with two colons', inject(function($rootScope, $compile) {
var element = $compile('
')($rootScope);
$rootScope.html = '
hello
';
expect($rootScope.$$watchers.length).toEqual(1);
$rootScope.$digest();
expect(element.text()).toEqual('hello');
expect($rootScope.$$watchers.length).toEqual(0);
$rootScope.html = '
hello
';
$rootScope.$digest();
expect(element.text()).toEqual('hello');
}));
});
describe('SCE enabled', function() {
it('should NOT set html for untrusted values', inject(function($rootScope, $compile) {
var element = $compile('
')($rootScope);
$rootScope.html = '
hello
';
expect(function() { $rootScope.$digest(); }).toThrowMinErr('$sce', 'unsafe', 'Attempting to use an unsafe value in a safe context.');
}));
it('should NOT set html for wrongly typed values', inject(function($rootScope, $compile, $sce) {
var element = $compile('
')($rootScope);
$rootScope.html = $sce.trustAsCss('
hello
');
expect(function() { $rootScope.$digest(); }).toThrowMinErr('$sce', 'unsafe', 'Attempting to use an unsafe value in a safe context.');
}));
it('should set html for trusted values', inject(function($rootScope, $compile, $sce) {
var element = $compile('
')($rootScope);
$rootScope.html = $sce.trustAsHtml('
hello
');
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('
hello
');
}));
it('should update html', inject(function($rootScope, $compile, $sce) {
var element = $compile('
')($rootScope);
$rootScope.html = $sce.trustAsHtml('hello');
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('hello');
$rootScope.html = $sce.trustAsHtml('goodbye');
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('goodbye');
}));
it('should not cause infinite recursion for trustAsHtml object watches',
inject(function($rootScope, $compile, $sce) {
// Ref: https://github.com/angular/angular.js/issues/3932
// If the binding is a function that creates a new value on every call via trustAs, we'll
// trigger an infinite digest if we don't take care of it.
var element = $compile('
')($rootScope);
$rootScope.getHtml = function() {
return $sce.trustAsHtml('
hello
');
};
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('
hello
');
}));
it('should handle custom $sce objects', function() {
function MySafeHtml(val) { this.val = val; }
module(function($provide) {
$provide.decorator('$sce', function($delegate) {
$delegate.trustAsHtml = function(html) { return new MySafeHtml(html); };
$delegate.getTrusted = function(type, mySafeHtml) { return mySafeHtml && mySafeHtml.val; };
$delegate.valueOf = function(v) { return v instanceof MySafeHtml ? v.val : v; };
return $delegate;
});
});
inject(function($rootScope, $compile, $sce) {
// Ref: https://github.com/angular/angular.js/issues/14526
// Previous code used toString for change detection, which fails for custom objects
// that don't override toString.
var element = $compile('
')($rootScope);
var html = 'hello';
$rootScope.getHtml = function() { return $sce.trustAsHtml(html); };
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('hello');
html = 'goodbye';
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('goodbye');
});
});
describe('when $sanitize is available', function() {
beforeEach(function() { module('ngSanitize'); });
it('should sanitize untrusted html', inject(function($rootScope, $compile) {
var element = $compile('
')($rootScope);
$rootScope.html = '
hello
';
$rootScope.$digest();
expect(lowercase(element.html())).toEqual('
hello
');
}));
});
});
});
describe('*[style]', function() {
// Support: IE9
// Some browsers throw when assignging to HTMLElement.style
function canAssignStyleProp() {
try {
window.document.createElement('div').style = 'margin-left: 10px';
return true;
} catch (e) {
return false;
}
}
it('should NOT set style for untrusted values', inject(function($rootScope, $compile) {
var element = $compile('
')($rootScope);
$rootScope.style = 'margin-left: 10px';
expect(function() { $rootScope.$digest(); }).toThrowMinErr('$sce', 'unsafe', 'Attempting to use an unsafe value in a safe context.');
}));
it('should NOT set style for wrongly typed values', inject(function($rootScope, $compile, $sce) {
var element = $compile('
')($rootScope);
$rootScope.style = $sce.trustAsHtml('margin-left: 10px');
expect(function() { $rootScope.$digest(); }).toThrowMinErr('$sce', 'unsafe', 'Attempting to use an unsafe value in a safe context.');
}));
if (canAssignStyleProp()) {
it('should set style for trusted values', inject(function($rootScope, $compile, $sce) {
var element = $compile('
')($rootScope);
$rootScope.style = $sce.trustAsCss('margin-left: 10px');
$rootScope.$digest();
// Support: IE
// IE allows assignments but does not register the styles
// Sometimes the value is '0px', sometimes ''
if (msie) {
expect(parseInt(element.css('margin-left'), 10) || 0).toBe(0);
} else {
expect(element.css('margin-left')).toEqual('10px');
}
}));
}
});
});