/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/core/test/acceptance/attributes_spec.ts
267 строк
9 KB
Matthieu Riegler
feat(core): Set default Component changeDetection strategy to OnPush
25 мар 2026, 02:25
25 мар 2026, 02:25
eae8f7e
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC 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.dev/license */ import {By, DomSanitizer, SafeUrl} from '@angular/platform-browser'; import {ChangeDetectionStrategy, Component, provideZoneChangeDetection} from '../../src/core'; import {TestBed} from '../../testing'; describe('attribute creation', () => { it('should create an element', () => { @Component({ template: `<div id="test" title="Hello"></div>`, standalone: false, changeDetection: ChangeDetectionStrategy.Eager, }) 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>`, standalone: false, changeDetection: ChangeDetectionStrategy.Eager, }) 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', () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [provideZoneChangeDetection()], }); }); it('should set attribute values', () => { @Component({ template: `<a [attr.href]="url"></a>`, standalone: false, changeDetection: ChangeDetectionStrategy.Eager, }) 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 be able to bind multiple attribute values per element', () => { @Component({ template: `<a [attr.id]="id" [attr.href]="url" [attr.tabindex]="'-1'"></a>`, standalone: false, changeDetection: ChangeDetectionStrategy.Eager, }) class Comp { url = 'https://angular.io/robots.txt'; id = 'my-link'; } 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.getAttribute('href')).toBe('https://angular.io/robots.txt'); expect(a.getAttribute('id')).toBe('my-link'); expect(a.getAttribute('tabindex')).toBe('-1'); }); it('should be able to bind multiple attributes in the presence of other bindings', () => { @Component({ template: `<a [id]="id" [attr.href]="url" [title]="'hello'"></a>`, standalone: false, changeDetection: ChangeDetectionStrategy.Eager, }) class Comp { url = 'https://angular.io/robots.txt'; id = 'my-link'; } 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.getAttribute('href')).toBe('https://angular.io/robots.txt'); expect(a.id).toBe('my-link'); expect(a.getAttribute('title')).toBe('hello'); }); it('should be able to bind attributes with interpolations', () => { @Component({ template: ` <button attr.id="my-{{ id }}-button" [attr.title]="title" attr.tabindex="{{ 1 + 3 + 7 }}" ></button>`, standalone: false, changeDetection: ChangeDetectionStrategy.Eager, }) class Comp { title = 'hello'; id = 'custom'; } TestBed.configureTestingModule({declarations: [Comp]}); const fixture = TestBed.createComponent(Comp); fixture.detectChanges(); const button = fixture.debugElement.query(By.css('button')).nativeElement; expect(button.getAttribute('id')).toBe('my-custom-button'); expect(button.getAttribute('tabindex')).toBe('11'); expect(button.getAttribute('title')).toBe('hello'); }); it('should be able to bind attributes both to parent and child nodes', () => { @Component({ template: ` <button attr.id="my-{{ id }}-button" [attr.title]="title" attr.tabindex="{{ 1 + 3 + 7 }}"> <span attr.title="span-{{ title }}" id="custom-span" [attr.tabindex]="-1"></span> </button> `, standalone: false, changeDetection: ChangeDetectionStrategy.Eager, }) class Comp { title = 'hello'; id = 'custom'; } TestBed.configureTestingModule({declarations: [Comp]}); const fixture = TestBed.createComponent(Comp); fixture.detectChanges(); const button = fixture.debugElement.query(By.css('button')).nativeElement; const span = fixture.debugElement.query(By.css('span')).nativeElement; expect(button.getAttribute('id')).toBe('my-custom-button'); expect(button.getAttribute('tabindex')).toBe('11'); expect(button.getAttribute('title')).toBe('hello'); expect(span.getAttribute('id')).toBe('custom-span'); expect(span.getAttribute('tabindex')).toBe('-1'); expect(span.getAttribute('title')).toBe('span-hello'); }); it('should sanitize attribute values', () => { @Component({ template: `<a [attr.href]="badUrl"></a>`, standalone: false, changeDetection: ChangeDetectionStrategy.Eager, }) 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.inject(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); }); }); describe('attribute interpolation', () => { it('should handle all varieties of interpolation', () => { @Component({ template: ` <div attr.title="a{{ a }}b{{ b }}c{{ c }}d{{ d }}e{{ e }}f{{ f }}g{{ g }}h{{ h }}i{{ i }}j" ></div> <div attr.title="a{{ a }}b{{ b }}c{{ c }}d{{ d }}e{{ e }}f{{ f }}g{{ g }}h{{ h }}i"></div> <div attr.title="a{{ a }}b{{ b }}c{{ c }}d{{ d }}e{{ e }}f{{ f }}g{{ g }}h"></div> <div attr.title="a{{ a }}b{{ b }}c{{ c }}d{{ d }}e{{ e }}f{{ f }}g"></div> <div attr.title="a{{ a }}b{{ b }}c{{ c }}d{{ d }}e{{ e }}f"></div> <div attr.title="a{{ a }}b{{ b }}c{{ c }}d{{ d }}e"></div> <div attr.title="a{{ a }}b{{ b }}c{{ c }}d"></div> <div attr.title="a{{ a }}b{{ b }}c"></div> <div attr.title="a{{ a }}b"></div> <div attr.title="{{ a }}"></div> `, standalone: false, changeDetection: ChangeDetectionStrategy.Eager, }) class App { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; i = 9; } TestBed.configureTestingModule({ declarations: [App], }); const fixture = TestBed.createComponent(App); fixture.detectChanges(); const divs = fixture.debugElement.queryAll(By.css('div[title]')); expect(divs.map((el) => el.nativeElement.getAttribute('title'))).toEqual([ 'a1b2c3d4e5f6g7h8i9j', 'a1b2c3d4e5f6g7h8i', 'a1b2c3d4e5f6g7h', 'a1b2c3d4e5f6g', 'a1b2c3d4e5f', 'a1b2c3d4e', 'a1b2c3d', 'a1b2c', 'a1b', '1', ]); }); });