test(ivy): move property and attribute tests to acceptance (#30321)
- splits existing property acceptance tests into property_binding and property_interpolation - ports tests from render3 instructions tests to acceptance tests - removes redundant or unnecessary tests that are covered by existing acceptance tests :) PR Close #30321
This commit is contained in:

committed by
Alex Rickabaugh

parent
f26f036286
commit
b1d45ee6d2
100
packages/core/test/acceptance/attributes_spec.ts
Normal file
100
packages/core/test/acceptance/attributes_spec.ts
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {By, DomSanitizer, SafeUrl} from '@angular/platform-browser';
|
||||
|
||||
describe('attribute creation', () => {
|
||||
it('should create an element', () => {
|
||||
@Component({
|
||||
template: `<div id="test" title="Hello"></div>`,
|
||||
})
|
||||
class Comp {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Comp]});
|
||||
const fixture = TestBed.createComponent(Comp);
|
||||
fixture.detectChanges();
|
||||
const div = fixture.debugElement.query(By.css('div')).nativeElement;
|
||||
expect(div.id).toEqual('test');
|
||||
expect(div.title).toEqual('Hello');
|
||||
});
|
||||
|
||||
it('should allow for setting xlink namespaced attributes', () => {
|
||||
@Component({
|
||||
template: `<div id="test" xlink:href="bar" title="Hello"></div>`,
|
||||
})
|
||||
class Comp {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Comp]});
|
||||
const fixture = TestBed.createComponent(Comp);
|
||||
fixture.detectChanges();
|
||||
|
||||
|
||||
const div = fixture.debugElement.query(By.css('div')).nativeElement;
|
||||
const attrs = div.attributes;
|
||||
|
||||
expect(attrs['id'].name).toEqual('id');
|
||||
expect(attrs['id'].namespaceURI).toEqual(null);
|
||||
expect(attrs['id'].value).toEqual('test');
|
||||
|
||||
expect(attrs['xlink:href'].name).toEqual('xlink:href');
|
||||
expect(attrs['xlink:href'].namespaceURI).toEqual('http://www.w3.org/1999/xlink');
|
||||
expect(attrs['xlink:href'].value).toEqual('bar');
|
||||
|
||||
expect(attrs['title'].name).toEqual('title');
|
||||
expect(attrs['title'].namespaceURI).toEqual(null);
|
||||
expect(attrs['title'].value).toEqual('Hello');
|
||||
});
|
||||
});
|
||||
|
||||
describe('attribute binding', () => {
|
||||
it('should set attribute values', () => {
|
||||
@Component({
|
||||
template: `<a [attr.href]="url"></a>`,
|
||||
})
|
||||
class Comp {
|
||||
url = 'https://angular.io/robots.txt';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Comp]});
|
||||
const fixture = TestBed.createComponent(Comp);
|
||||
fixture.detectChanges();
|
||||
|
||||
const a = fixture.debugElement.query(By.css('a')).nativeElement;
|
||||
// NOTE: different browsers will add `//` into the URI.
|
||||
expect(a.href).toEqual('https://angular.io/robots.txt');
|
||||
});
|
||||
|
||||
it('should sanitize attribute values', () => {
|
||||
@Component({
|
||||
template: `<a [attr.href]="badUrl"></a>`,
|
||||
})
|
||||
class Comp {
|
||||
badUrl: string|SafeUrl = 'javascript:true';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Comp]});
|
||||
const fixture = TestBed.createComponent(Comp);
|
||||
fixture.detectChanges();
|
||||
|
||||
const a = fixture.debugElement.query(By.css('a')).nativeElement;
|
||||
// NOTE: different browsers will add `//` into the URI.
|
||||
expect(a.href.indexOf('unsafe:')).toBe(0);
|
||||
|
||||
const domSanitizer: DomSanitizer = TestBed.get(DomSanitizer);
|
||||
fixture.componentInstance.badUrl =
|
||||
domSanitizer.bypassSecurityTrustUrl('javascript:alert("this is fine")');
|
||||
fixture.detectChanges();
|
||||
|
||||
// should not start with `unsafe:`.
|
||||
expect(a.href.indexOf('unsafe:')).toBe(-1);
|
||||
});
|
||||
});
|
138
packages/core/test/acceptance/property_binding_spec.ts
Normal file
138
packages/core/test/acceptance/property_binding_spec.ts
Normal file
@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {By, DomSanitizer, SafeUrl} from '@angular/platform-browser';
|
||||
|
||||
describe('property bindings', () => {
|
||||
it('should update bindings when value changes', () => {
|
||||
@Component({
|
||||
template: `<a [title]="title"></a>`,
|
||||
})
|
||||
class Comp {
|
||||
title = 'Hello';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Comp]});
|
||||
const fixture = TestBed.createComponent(Comp);
|
||||
fixture.detectChanges();
|
||||
let a = fixture.debugElement.query(By.css('a')).nativeElement;
|
||||
expect(a.title).toBe('Hello');
|
||||
|
||||
fixture.componentInstance.title = 'World';
|
||||
fixture.detectChanges();
|
||||
expect(a.title).toBe('World');
|
||||
});
|
||||
|
||||
it('should not update bindings when value does not change', () => {
|
||||
@Component({
|
||||
template: `<a [title]="title"></a>`,
|
||||
})
|
||||
class Comp {
|
||||
title = 'Hello';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Comp]});
|
||||
const fixture = TestBed.createComponent(Comp);
|
||||
fixture.detectChanges();
|
||||
let a = fixture.debugElement.query(By.css('a')).nativeElement;
|
||||
expect(a.title).toBe('Hello');
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(a.title).toBe('Hello');
|
||||
});
|
||||
|
||||
it('should bind to properties whose names do not correspond to their attribute names', () => {
|
||||
@Component({template: '<label [for]="forValue"></label>'})
|
||||
class MyComp {
|
||||
forValue?: string;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
const labelNode = fixture.debugElement.query(By.css('label'));
|
||||
|
||||
fixture.componentInstance.forValue = 'some-input';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(labelNode.nativeElement.getAttribute('for')).toBe('some-input');
|
||||
|
||||
fixture.componentInstance.forValue = 'some-textarea';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(labelNode.nativeElement.getAttribute('for')).toBe('some-textarea');
|
||||
});
|
||||
|
||||
it('should not map properties whose names do not correspond to their attribute names, ' +
|
||||
'if they correspond to inputs',
|
||||
() => {
|
||||
|
||||
@Component({template: '', selector: 'my-comp'})
|
||||
class MyComp {
|
||||
@Input() for !:string;
|
||||
}
|
||||
|
||||
@Component({template: '<my-comp [for]="forValue"></my-comp>'})
|
||||
class App {
|
||||
forValue?: string;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App, MyComp]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
const myCompNode = fixture.debugElement.query(By.directive(MyComp));
|
||||
fixture.componentInstance.forValue = 'hello';
|
||||
fixture.detectChanges();
|
||||
expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy();
|
||||
expect(myCompNode.componentInstance.for).toBe('hello');
|
||||
|
||||
fixture.componentInstance.forValue = 'hej';
|
||||
fixture.detectChanges();
|
||||
expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy();
|
||||
expect(myCompNode.componentInstance.for).toBe('hej');
|
||||
});
|
||||
|
||||
it('should use the sanitizer in bound properties', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<a [href]="url">
|
||||
`
|
||||
})
|
||||
class App {
|
||||
url: string|SafeUrl = 'javascript:alert("haha, I am taking over your computer!!!");';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
const a = fixture.nativeElement.querySelector('a');
|
||||
|
||||
expect(a.href.indexOf('unsafe:')).toBe(0);
|
||||
|
||||
const domSanitzer: DomSanitizer = TestBed.get(DomSanitizer);
|
||||
fixture.componentInstance.url =
|
||||
domSanitzer.bypassSecurityTrustUrl('javascript:alert("the developer wanted this");');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(a.href.indexOf('unsafe:')).toBe(-1);
|
||||
});
|
||||
|
||||
it('should not stringify non-string values', () => {
|
||||
@Component({
|
||||
template: `<input [required]="isRequired"/>`,
|
||||
})
|
||||
class Comp {
|
||||
isRequired = false;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Comp]});
|
||||
const fixture = TestBed.createComponent(Comp);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.debugElement.query(By.css('input')).nativeElement.required).toBe(false);
|
||||
});
|
||||
});
|
@ -5,82 +5,12 @@
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Component} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
import {of } from 'rxjs';
|
||||
|
||||
describe('property instructions', () => {
|
||||
it('should bind to properties whose names do not correspond to their attribute names', () => {
|
||||
@Component({template: '<label [for]="forValue"></label>'})
|
||||
class MyComp {
|
||||
forValue?: string;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
const labelNode = fixture.debugElement.query(By.css('label'));
|
||||
|
||||
fixture.componentInstance.forValue = 'some-input';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(labelNode.nativeElement.getAttribute('for')).toBe('some-input');
|
||||
|
||||
fixture.componentInstance.forValue = 'some-textarea';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(labelNode.nativeElement.getAttribute('for')).toBe('some-textarea');
|
||||
});
|
||||
|
||||
it('should not allow unsanitary urls in bound properties', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<img [src]="naughty">
|
||||
`
|
||||
})
|
||||
class App {
|
||||
naughty = 'javascript:alert("haha, I am taking over your computer!!!");';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
const img = fixture.nativeElement.querySelector('img');
|
||||
|
||||
expect(img.src.indexOf('unsafe:')).toBe(0);
|
||||
});
|
||||
|
||||
|
||||
it('should not map properties whose names do not correspond to their attribute names, ' +
|
||||
'if they correspond to inputs',
|
||||
() => {
|
||||
|
||||
@Component({template: '', selector: 'my-comp'})
|
||||
class MyComp {
|
||||
@Input() for !:string;
|
||||
}
|
||||
|
||||
@Component({template: '<my-comp [for]="forValue"></my-comp>'})
|
||||
class App {
|
||||
forValue?: string;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App, MyComp]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
const myCompNode = fixture.debugElement.query(By.directive(MyComp));
|
||||
fixture.componentInstance.forValue = 'hello';
|
||||
fixture.detectChanges();
|
||||
expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy();
|
||||
expect(myCompNode.componentInstance.for).toBe('hello');
|
||||
|
||||
fixture.componentInstance.forValue = 'hej';
|
||||
fixture.detectChanges();
|
||||
expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy();
|
||||
expect(myCompNode.componentInstance.for).toBe('hej');
|
||||
});
|
||||
|
||||
describe('property interpolation', () => {
|
||||
it('should handle all flavors of interpolated properties', () => {
|
||||
@Component({
|
||||
template: `
|
||||
@ -230,4 +160,70 @@ describe('property instructions', () => {
|
||||
.toEqual(
|
||||
`http://g.com/?one=1&two=2&three=3&four=4&five=5&six=6&seven=7&eight=8&nine=9&ten=10`);
|
||||
});
|
||||
|
||||
it('should support the chained use cases of propertyInterpolate instructions', () => {
|
||||
// The below *just happens* to have two attributes in a row that have the same interpolation
|
||||
// count.
|
||||
@Component({
|
||||
template: `
|
||||
<img title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i{{nine}}j" alt="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i{{nine}}j"/>
|
||||
<img title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i" alt="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h{{eight}}i"/>
|
||||
<img title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h" alt="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g{{seven}}h"/>
|
||||
<img title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g" alt="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f{{six}}g"/>
|
||||
<img title="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f" alt="a{{one}}b{{two}}c{{three}}d{{four}}e{{five}}f"/>
|
||||
<img title="a{{one}}b{{two}}c{{three}}d{{four}}e" alt="a{{one}}b{{two}}c{{three}}d{{four}}e"/>
|
||||
<img title="a{{one}}b{{two}}c{{three}}d" alt="a{{one}}b{{two}}c{{three}}d"/>
|
||||
<img title="a{{one}}b{{two}}c" alt="a{{one}}b{{two}}c"/>
|
||||
<img title="a{{one}}b" alt="a{{one}}b"/>
|
||||
<img title="{{one}}" alt="{{one}}"/>
|
||||
`
|
||||
})
|
||||
class AppComp {
|
||||
one = 1;
|
||||
two = 2;
|
||||
three = 3;
|
||||
four = 4;
|
||||
five = 5;
|
||||
six = 6;
|
||||
seven = 7;
|
||||
eight = 8;
|
||||
nine = 9;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [AppComp]});
|
||||
const fixture = TestBed.createComponent(AppComp);
|
||||
fixture.detectChanges();
|
||||
|
||||
const titles = Array.from(fixture.nativeElement.querySelectorAll('img[title]'))
|
||||
.map((img: HTMLImageElement) => img.title);
|
||||
|
||||
expect(titles).toEqual([
|
||||
'a1b2c3d4e5f6g7h8i9j',
|
||||
'a1b2c3d4e5f6g7h8i',
|
||||
'a1b2c3d4e5f6g7h',
|
||||
'a1b2c3d4e5f6g',
|
||||
'a1b2c3d4e5f',
|
||||
'a1b2c3d4e',
|
||||
'a1b2c3d',
|
||||
'a1b2c',
|
||||
'a1b',
|
||||
'1',
|
||||
]);
|
||||
|
||||
const others = Array.from(fixture.nativeElement.querySelectorAll('img[alt]'))
|
||||
.map((img: HTMLImageElement) => img.alt);
|
||||
|
||||
expect(others).toEqual([
|
||||
'a1b2c3d4e5f6g7h8i9j',
|
||||
'a1b2c3d4e5f6g7h8i',
|
||||
'a1b2c3d4e5f6g7h',
|
||||
'a1b2c3d4e5f6g',
|
||||
'a1b2c3d4e5f',
|
||||
'a1b2c3d4e',
|
||||
'a1b2c3d',
|
||||
'a1b2c',
|
||||
'a1b',
|
||||
'1',
|
||||
]);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user