refactor(core): Removed linker test references to TestComponentBuilder (#10903)
Removed references to TestComponentBuilder from: query_integration_spec.ts regression_integration_spec.ts security_integration_spec.ts view_injector_integration_spec.ts
This commit is contained in:
parent
c48021ab97
commit
a5c0349d88
File diff suppressed because it is too large
Load Diff
|
@ -10,7 +10,7 @@ import {NgClass, NgIf} from '@angular/common';
|
|||
import {Component, Injector, OpaqueToken, Pipe, PipeTransform, forwardRef} from '@angular/core';
|
||||
import {ViewMetadata} from '@angular/core/src/metadata/view';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {AsyncTestCompleter, TestComponentBuilder, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
|
||||
import {beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
|
||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||
|
||||
export function main() {
|
||||
|
@ -23,199 +23,134 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||
// Place to put reproductions for regressions
|
||||
describe('regressions', () => {
|
||||
|
||||
describe('platform pipes', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler({useJit: useJit});
|
||||
TestBed.configureTestingModule({declarations: [PlatformPipe]});
|
||||
});
|
||||
beforeEach(() => { TestBed.configureTestingModule({declarations: [MyComp1, PlatformPipe]}); });
|
||||
|
||||
it('should overwrite them by custom pipes',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
tcb.overrideView(
|
||||
MyComp1,
|
||||
new ViewMetadata({template: '{{true | somePipe}}', pipes: [CustomPipe]}))
|
||||
.createAsync(MyComp1)
|
||||
.then((fixture) => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('someCustomPipe');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
describe('platform pipes', () => {
|
||||
beforeEach(() => { TestBed.configureCompiler({useJit: useJit}); });
|
||||
|
||||
it('should overwrite them by custom pipes', () => {
|
||||
TestBed.configureTestingModule({declarations: [CustomPipe]});
|
||||
const template = '{{true | somePipe}}';
|
||||
TestBed.overrideComponent(MyComp1, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp1);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('someCustomPipe');
|
||||
});
|
||||
});
|
||||
|
||||
describe('expressions', () => {
|
||||
it('should evaluate conditional and boolean operators with right precedence - #8244', () => {
|
||||
const template = `{{'red' + (true ? ' border' : '')}}`;
|
||||
TestBed.overrideComponent(MyComp1, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp1);
|
||||
|
||||
it('should evaluate conditional and boolean operators with right precedence - #8244',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
tcb.overrideView(
|
||||
MyComp1, new ViewMetadata({template: `{{'red' + (true ? ' border' : '')}}`}))
|
||||
.createAsync(MyComp1)
|
||||
.then((fixture) => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('red border');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('red border');
|
||||
});
|
||||
|
||||
it('should evaluate conditional and unary operators with right precedence - #8235',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
tcb.overrideView(MyComp1, new ViewMetadata({template: `{{!null?.length}}`}))
|
||||
.createAsync(MyComp1)
|
||||
.then((fixture) => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('true');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
it('should evaluate conditional and unary operators with right precedence - #8235', () => {
|
||||
const template = `{{!null?.length}}`;
|
||||
TestBed.overrideComponent(MyComp1, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp1);
|
||||
|
||||
it('should only evaluate stateful pipes once - #10639',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
tcb.overrideView(
|
||||
MyComp1,
|
||||
new ViewMetadata(
|
||||
{template: '{{(null|countingPipe)?.value}}', pipes: [CountingPipe]}))
|
||||
.createAsync(MyComp1)
|
||||
.then(fixture => {
|
||||
CountingPipe.reset();
|
||||
fixture.detectChanges(/* checkNoChanges */ false);
|
||||
expect(fixture.nativeElement).toHaveText('counting pipe value');
|
||||
expect(CountingPipe.calls).toBe(1);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('true');
|
||||
});
|
||||
|
||||
it('should only evaluate methods once - #10639',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
tcb.overrideView(MyCountingComp, new ViewMetadata({template: '{{method()?.value}}'}))
|
||||
.createAsync(MyCountingComp)
|
||||
.then(fixture => {
|
||||
MyCountingComp.reset();
|
||||
fixture.detectChanges(/* checkNoChanges */ false);
|
||||
expect(fixture.nativeElement).toHaveText('counting method value');
|
||||
expect(MyCountingComp.calls).toBe(1);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
it('should only evaluate stateful pipes once - #10639', () => {
|
||||
TestBed.configureTestingModule({declarations: [CountingPipe]});
|
||||
const template = '{{(null|countingPipe)?.value}}';
|
||||
TestBed.overrideComponent(MyComp1, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp1);
|
||||
|
||||
CountingPipe.reset();
|
||||
fixture.detectChanges(/* checkNoChanges */ false);
|
||||
expect(fixture.nativeElement).toHaveText('counting pipe value');
|
||||
expect(CountingPipe.calls).toBe(1);
|
||||
});
|
||||
|
||||
it('should only evaluate methods once - #10639', () => {
|
||||
TestBed.configureTestingModule({declarations: [MyCountingComp]});
|
||||
const template = '{{method()?.value}}';
|
||||
TestBed.overrideComponent(MyCountingComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyCountingComp);
|
||||
|
||||
MyCountingComp.reset();
|
||||
fixture.detectChanges(/* checkNoChanges */ false);
|
||||
expect(fixture.nativeElement).toHaveText('counting method value');
|
||||
expect(MyCountingComp.calls).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('providers', () => {
|
||||
function createInjector(tcb: TestComponentBuilder, proviers: any[]): Promise<Injector> {
|
||||
return tcb.overrideProviders(MyComp1, [proviers])
|
||||
.createAsync(MyComp1)
|
||||
.then((fixture) => fixture.componentInstance.injector);
|
||||
function createInjector(providers: any[]): Injector {
|
||||
TestBed.overrideComponent(MyComp1, {add: {providers}});
|
||||
return TestBed.createComponent(MyComp1).componentInstance.injector;
|
||||
}
|
||||
|
||||
it('should support providers with an OpaqueToken that contains a `.` in the name',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
var token = new OpaqueToken('a.b');
|
||||
var tokenValue = 1;
|
||||
createInjector(tcb, [
|
||||
{provide: token, useValue: tokenValue}
|
||||
]).then((injector: Injector) => {
|
||||
expect(injector.get(token)).toEqual(tokenValue);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
it('should support providers with an OpaqueToken that contains a `.` in the name', () => {
|
||||
var token = new OpaqueToken('a.b');
|
||||
var tokenValue = 1;
|
||||
const injector = createInjector([{provide: token, useValue: tokenValue}]);
|
||||
expect(injector.get(token)).toEqual(tokenValue);
|
||||
});
|
||||
|
||||
it('should support providers with string token with a `.` in it',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
var token = 'a.b';
|
||||
var tokenValue = 1;
|
||||
createInjector(tcb, [
|
||||
{provide: token, useValue: tokenValue}
|
||||
]).then((injector: Injector) => {
|
||||
expect(injector.get(token)).toEqual(tokenValue);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
it('should support providers with string token with a `.` in it', () => {
|
||||
var token = 'a.b';
|
||||
var tokenValue = 1;
|
||||
const injector = createInjector([{provide: token, useValue: tokenValue}]);
|
||||
|
||||
it('should support providers with an anonymous function',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
var token = () => true;
|
||||
var tokenValue = 1;
|
||||
createInjector(tcb, [
|
||||
{provide: token, useValue: tokenValue}
|
||||
]).then((injector: Injector) => {
|
||||
expect(injector.get(token)).toEqual(tokenValue);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
expect(injector.get(token)).toEqual(tokenValue);
|
||||
});
|
||||
|
||||
it('should support providers with an OpaqueToken that has a StringMap as value',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
var token1 = new OpaqueToken('someToken');
|
||||
var token2 = new OpaqueToken('someToken');
|
||||
var tokenValue1 = {'a': 1};
|
||||
var tokenValue2 = {'a': 1};
|
||||
createInjector(tcb, [
|
||||
{provide: token1, useValue: tokenValue1},
|
||||
{provide: token2, useValue: tokenValue2}
|
||||
]).then((injector: Injector) => {
|
||||
expect(injector.get(token1)).toEqual(tokenValue1);
|
||||
expect(injector.get(token2)).toEqual(tokenValue2);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
it('should support providers with an anonymous function', () => {
|
||||
var token = () => true;
|
||||
var tokenValue = 1;
|
||||
const injector = createInjector([{provide: token, useValue: tokenValue}]);
|
||||
|
||||
expect(injector.get(token)).toEqual(tokenValue);
|
||||
});
|
||||
|
||||
it('should support providers with an OpaqueToken that has a StringMap as value', () => {
|
||||
var token1 = new OpaqueToken('someToken');
|
||||
var token2 = new OpaqueToken('someToken');
|
||||
var tokenValue1 = {'a': 1};
|
||||
var tokenValue2 = {'a': 1};
|
||||
const injector = createInjector(
|
||||
[{provide: token1, useValue: tokenValue1}, {provide: token2, useValue: tokenValue2}]);
|
||||
|
||||
expect(injector.get(token1)).toEqual(tokenValue1);
|
||||
expect(injector.get(token2)).toEqual(tokenValue2);
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow logging a previous elements class binding via interpolation',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
tcb.overrideTemplate(
|
||||
MyComp1, `<div [class.a]="true" #el>Class: {{el.className}}</div>`)
|
||||
.createAsync(MyComp1)
|
||||
.then((fixture) => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('Class: a');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
it('should allow logging a previous elements class binding via interpolation', () => {
|
||||
const template = `<div [class.a]="true" #el>Class: {{el.className}}</div>`;
|
||||
TestBed.overrideComponent(MyComp1, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp1);
|
||||
|
||||
it('should support ngClass before a component and content projection inside of an ngIf',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: any) => {
|
||||
tcb.overrideView(
|
||||
MyComp1, new ViewMetadata({
|
||||
template: `A<cmp-content *ngIf="true" [ngClass]="'red'">B</cmp-content>C`,
|
||||
directives: [NgClass, NgIf, CmpWithNgContent]
|
||||
}))
|
||||
.createAsync(MyComp1)
|
||||
.then((fixture) => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('ABC');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('Class: a');
|
||||
});
|
||||
|
||||
it('should handle mutual recursion entered from multiple sides - #7084',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: any) => {
|
||||
tcb.createAsync(FakeRecursiveComp).then((fixture) => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('[]');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
it('should support ngClass before a component and content projection inside of an ngIf', () => {
|
||||
TestBed.configureTestingModule({declarations: [CmpWithNgContent]});
|
||||
const template = `A<cmp-content *ngIf="true" [ngClass]="'red'">B</cmp-content>C`;
|
||||
TestBed.overrideComponent(MyComp1, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp1);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('ABC');
|
||||
});
|
||||
|
||||
it('should handle mutual recursion entered from multiple sides - #7084', () => {
|
||||
TestBed.configureTestingModule({declarations: [FakeRecursiveComp, LeftComp, RightComp]});
|
||||
const fixture = TestBed.createComponent(FakeRecursiveComp);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('[]');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -262,10 +197,6 @@ class CountingPipe implements PipeTransform {
|
|||
@Component({
|
||||
selector: 'left',
|
||||
template: `L<right *ngIf="false"></right>`,
|
||||
directives: [
|
||||
NgIf,
|
||||
forwardRef(() => RightComp),
|
||||
]
|
||||
})
|
||||
class LeftComp {
|
||||
}
|
||||
|
@ -273,10 +204,6 @@ class LeftComp {
|
|||
@Component({
|
||||
selector: 'right',
|
||||
template: `R<left *ngIf="false"></left>`,
|
||||
directives: [
|
||||
NgIf,
|
||||
forwardRef(() => LeftComp),
|
||||
]
|
||||
})
|
||||
class RightComp {
|
||||
}
|
||||
|
@ -284,11 +211,6 @@ class RightComp {
|
|||
@Component({
|
||||
selector: 'fakeRecursiveComp',
|
||||
template: `[<left *ngIf="false"></left><right *ngIf="false"></right>]`,
|
||||
directives: [
|
||||
NgIf,
|
||||
forwardRef(() => LeftComp),
|
||||
forwardRef(() => RightComp),
|
||||
]
|
||||
})
|
||||
export class FakeRecursiveComp {
|
||||
}
|
||||
|
|
|
@ -7,42 +7,30 @@
|
|||
*/
|
||||
|
||||
import {Component} from '@angular/core/src/metadata';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {AsyncTestCompleter, TestComponentBuilder, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
||||
import {TestBed, getTestBed} from '@angular/core/testing';
|
||||
import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
import {DomSanitizationService} from '@angular/platform-browser/src/security/dom_sanitization_service';
|
||||
|
||||
|
||||
export function main() {
|
||||
describe('jit', () => { declareTests({useJit: true}); });
|
||||
|
||||
describe('no jit', () => { declareTests({useJit: false}); });
|
||||
}
|
||||
|
||||
@Component({selector: 'my-comp', template: '', directives: []})
|
||||
@Component({selector: 'my-comp', template: ''})
|
||||
class SecuredComponent {
|
||||
ctxProp: string;
|
||||
constructor() { this.ctxProp = 'some value'; }
|
||||
}
|
||||
|
||||
function itAsync(msg: string, injections: Function[], f: Function): void;
|
||||
function itAsync(
|
||||
msg: string, f: (tcb: TestComponentBuilder, atc: AsyncTestCompleter) => void): void;
|
||||
function itAsync(
|
||||
msg: string, f: Function[] | ((tcb: TestComponentBuilder, atc: AsyncTestCompleter) => void),
|
||||
fn?: Function): void {
|
||||
if (f instanceof Function) {
|
||||
it(msg, inject([TestComponentBuilder, AsyncTestCompleter], <Function>f));
|
||||
} else {
|
||||
let injections = f;
|
||||
it(msg, inject(injections, fn));
|
||||
}
|
||||
}
|
||||
|
||||
function declareTests({useJit}: {useJit: boolean}) {
|
||||
describe('security integration tests', function() {
|
||||
|
||||
beforeEach(() => { TestBed.configureCompiler({useJit: useJit}); });
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler({useJit: useJit});
|
||||
TestBed.configureTestingModule({declarations: [SecuredComponent]});
|
||||
});
|
||||
|
||||
let originalLog: (msg: any) => any;
|
||||
beforeEach(() => {
|
||||
|
@ -52,175 +40,137 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||
afterEach(() => { getDOM().log = originalLog; });
|
||||
|
||||
|
||||
itAsync(
|
||||
'should disallow binding on*', (tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
let tpl = `<div [attr.onclick]="ctxProp"></div>`;
|
||||
tcb.overrideTemplate(SecuredComponent, tpl)
|
||||
.createAsync(SecuredComponent)
|
||||
.then(v => async.done(new Error('unexpected success')))
|
||||
.catch((e) => {
|
||||
expect(e.message).toContain(
|
||||
`Template parse errors:\n` +
|
||||
`Binding to event attribute 'onclick' is disallowed ` +
|
||||
`for security reasons, please use (click)=... `);
|
||||
async.done();
|
||||
return null;
|
||||
});
|
||||
});
|
||||
it('should disallow binding on*', () => {
|
||||
const template = `<div [attr.onclick]="ctxProp"></div>`;
|
||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||
try {
|
||||
TestBed.createComponent(SecuredComponent);
|
||||
throw 'Should throw';
|
||||
} catch (e) {
|
||||
expect(e.message).toContain(
|
||||
`Template parse errors:\n` +
|
||||
`Binding to event attribute 'onclick' is disallowed ` +
|
||||
`for security reasons, please use (click)=... `);
|
||||
}
|
||||
});
|
||||
|
||||
describe('safe HTML values', function() {
|
||||
itAsync(
|
||||
'should not escape values marked as trusted',
|
||||
[TestComponentBuilder, AsyncTestCompleter, DomSanitizationService],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter,
|
||||
sanitizer: DomSanitizationService) => {
|
||||
let tpl = `<a [href]="ctxProp">Link Title</a>`;
|
||||
tcb.overrideTemplate(SecuredComponent, tpl)
|
||||
.createAsync(SecuredComponent)
|
||||
.then((fixture) => {
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
let trusted = sanitizer.bypassSecurityTrustUrl('javascript:alert(1)');
|
||||
ci.ctxProp = trusted;
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getProperty(e, 'href')).toEqual('javascript:alert(1)');
|
||||
it('should not escape values marked as trusted', () => {
|
||||
const template = `<a [href]="ctxProp">Link Title</a>`;
|
||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||
const fixture = TestBed.createComponent(SecuredComponent);
|
||||
const sanitizer: DomSanitizationService = getTestBed().get(DomSanitizationService);
|
||||
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
let trusted = sanitizer.bypassSecurityTrustUrl('javascript:alert(1)');
|
||||
ci.ctxProp = trusted;
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getProperty(e, 'href')).toEqual('javascript:alert(1)');
|
||||
});
|
||||
|
||||
itAsync(
|
||||
'should error when using the wrong trusted value',
|
||||
[TestComponentBuilder, AsyncTestCompleter, DomSanitizationService],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter,
|
||||
sanitizer: DomSanitizationService) => {
|
||||
let tpl = `<a [href]="ctxProp">Link Title</a>`;
|
||||
tcb.overrideTemplate(SecuredComponent, tpl)
|
||||
.createAsync(SecuredComponent)
|
||||
.then((fixture) => {
|
||||
let trusted = sanitizer.bypassSecurityTrustScript('javascript:alert(1)');
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
ci.ctxProp = trusted;
|
||||
expect(() => fixture.detectChanges())
|
||||
.toThrowError(/Required a safe URL, got a Script/);
|
||||
it('should error when using the wrong trusted value', () => {
|
||||
const template = `<a [href]="ctxProp">Link Title</a>`;
|
||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||
const fixture = TestBed.createComponent(SecuredComponent);
|
||||
const sanitizer: DomSanitizationService = getTestBed().get(DomSanitizationService);
|
||||
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
let trusted = sanitizer.bypassSecurityTrustScript('javascript:alert(1)');
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
ci.ctxProp = trusted;
|
||||
expect(() => fixture.detectChanges()).toThrowError(/Required a safe URL, got a Script/);
|
||||
});
|
||||
|
||||
itAsync(
|
||||
'should warn when using in string interpolation',
|
||||
[TestComponentBuilder, AsyncTestCompleter, DomSanitizationService],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter,
|
||||
sanitizer: DomSanitizationService) => {
|
||||
let tpl = `<a href="/foo/{{ctxProp}}">Link Title</a>`;
|
||||
tcb.overrideTemplate(SecuredComponent, tpl)
|
||||
.createAsync(SecuredComponent)
|
||||
.then((fixture) => {
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let trusted = sanitizer.bypassSecurityTrustUrl('bar/baz');
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
ci.ctxProp = trusted;
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getProperty(e, 'href')).toMatch(/SafeValue(%20| )must(%20| )use/);
|
||||
it('should warn when using in string interpolation', () => {
|
||||
const template = `<a href="/foo/{{ctxProp}}">Link Title</a>`;
|
||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||
const fixture = TestBed.createComponent(SecuredComponent);
|
||||
const sanitizer: DomSanitizationService = getTestBed().get(DomSanitizationService);
|
||||
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let trusted = sanitizer.bypassSecurityTrustUrl('bar/baz');
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
ci.ctxProp = trusted;
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getProperty(e, 'href')).toMatch(/SafeValue(%20| )must(%20| )use/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sanitizing', () => {
|
||||
itAsync(
|
||||
'should escape unsafe attributes',
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
let tpl = `<a [href]="ctxProp">Link Title</a>`;
|
||||
tcb.overrideTemplate(SecuredComponent, tpl)
|
||||
.createAsync(SecuredComponent)
|
||||
.then((fixture) => {
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
ci.ctxProp = 'hello';
|
||||
fixture.detectChanges();
|
||||
// In the browser, reading href returns an absolute URL. On the server side,
|
||||
// it just echoes back the property.
|
||||
expect(getDOM().getProperty(e, 'href')).toMatch(/.*\/?hello$/);
|
||||
it('should escape unsafe attributes', () => {
|
||||
const template = `<a [href]="ctxProp">Link Title</a>`;
|
||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||
const fixture = TestBed.createComponent(SecuredComponent);
|
||||
|
||||
ci.ctxProp = 'javascript:alert(1)';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getProperty(e, 'href')).toEqual('unsafe:javascript:alert(1)');
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
ci.ctxProp = 'hello';
|
||||
fixture.detectChanges();
|
||||
// In the browser, reading href returns an absolute URL. On the server side,
|
||||
// it just echoes back the property.
|
||||
expect(getDOM().getProperty(e, 'href')).toMatch(/.*\/?hello$/);
|
||||
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
ci.ctxProp = 'javascript:alert(1)';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getProperty(e, 'href')).toEqual('unsafe:javascript:alert(1)');
|
||||
});
|
||||
|
||||
itAsync(
|
||||
'should escape unsafe style values',
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
let tpl = `<div [style.background]="ctxProp">Text</div>`;
|
||||
tcb.overrideTemplate(SecuredComponent, tpl)
|
||||
.createAsync(SecuredComponent)
|
||||
.then((fixture) => {
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
// Make sure binding harmless values works.
|
||||
ci.ctxProp = 'red';
|
||||
fixture.detectChanges();
|
||||
// In some browsers, this will contain the full background specification, not just
|
||||
// the color.
|
||||
expect(getDOM().getStyle(e, 'background')).toMatch(/red.*/);
|
||||
it('should escape unsafe style values', () => {
|
||||
const template = `<div [style.background]="ctxProp">Text</div>`;
|
||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||
const fixture = TestBed.createComponent(SecuredComponent);
|
||||
|
||||
ci.ctxProp = 'url(javascript:evil())';
|
||||
fixture.detectChanges();
|
||||
// Updated value gets rejected, no value change.
|
||||
expect(getDOM().getStyle(e, 'background')).not.toContain('javascript');
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
// Make sure binding harmless values works.
|
||||
ci.ctxProp = 'red';
|
||||
fixture.detectChanges();
|
||||
// In some browsers, this will contain the full background specification, not just
|
||||
// the color.
|
||||
expect(getDOM().getStyle(e, 'background')).toMatch(/red.*/);
|
||||
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
ci.ctxProp = 'url(javascript:evil())';
|
||||
fixture.detectChanges();
|
||||
// Updated value gets rejected, no value change.
|
||||
expect(getDOM().getStyle(e, 'background')).not.toContain('javascript');
|
||||
});
|
||||
|
||||
itAsync(
|
||||
'should escape unsafe SVG attributes',
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
let tpl = `<svg:circle [xlink:href]="ctxProp">Text</svg:circle>`;
|
||||
tcb.overrideTemplate(SecuredComponent, tpl)
|
||||
.createAsync(SecuredComponent)
|
||||
.then(v => async.done(new Error('unexpected success')))
|
||||
.catch((e) => {
|
||||
expect(e.message).toContain(`Can't bind to 'xlink:href'`);
|
||||
async.done();
|
||||
return null;
|
||||
});
|
||||
});
|
||||
it('should escape unsafe SVG attributes', () => {
|
||||
const template = `<svg:circle [xlink:href]="ctxProp">Text</svg:circle>`;
|
||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||
|
||||
itAsync(
|
||||
'should escape unsafe HTML values',
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
let tpl = `<div [innerHTML]="ctxProp">Text</div>`;
|
||||
tcb.overrideTemplate(SecuredComponent, tpl)
|
||||
.createAsync(SecuredComponent)
|
||||
.then((fixture) => {
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
// Make sure binding harmless values works.
|
||||
ci.ctxProp = 'some <p>text</p>';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getInnerHTML(e)).toEqual('some <p>text</p>');
|
||||
try {
|
||||
TestBed.createComponent(SecuredComponent);
|
||||
throw 'Should throw';
|
||||
} catch (e) {
|
||||
expect(e.message).toContain(`Can't bind to 'xlink:href'`);
|
||||
}
|
||||
});
|
||||
|
||||
ci.ctxProp = 'ha <script>evil()</script>';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getInnerHTML(e)).toEqual('ha evil()');
|
||||
it('should escape unsafe HTML values', () => {
|
||||
const template = `<div [innerHTML]="ctxProp">Text</div>`;
|
||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||
const fixture = TestBed.createComponent(SecuredComponent);
|
||||
|
||||
ci.ctxProp = 'also <img src="x" onerror="evil()"> evil';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getInnerHTML(e)).toEqual('also <img src="x"> evil');
|
||||
let e = fixture.debugElement.children[0].nativeElement;
|
||||
let ci = fixture.debugElement.componentInstance;
|
||||
// Make sure binding harmless values works.
|
||||
ci.ctxProp = 'some <p>text</p>';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getInnerHTML(e)).toEqual('some <p>text</p>');
|
||||
|
||||
ci.ctxProp = 'also <iframe srcdoc="evil"></iframe> evil';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getInnerHTML(e)).toEqual('also evil');
|
||||
ci.ctxProp = 'ha <script>evil()</script>';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getInnerHTML(e)).toEqual('ha evil()');
|
||||
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
ci.ctxProp = 'also <img src="x" onerror="evil()"> evil';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getInnerHTML(e)).toEqual('also <img src="x"> evil');
|
||||
|
||||
ci.ctxProp = 'also <iframe srcdoc="evil"></iframe> evil';
|
||||
fixture.detectChanges();
|
||||
expect(getDOM().getInnerHTML(e)).toEqual('also evil');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue