Тестирование директив атрибутов
Директива атрибута изменяет поведение элемента, компонента или другой директивы. Её название отражает способ применения директивы: в виде атрибута элемента-хоста.
Тестирование директивы Highlight
Директива Highlight в примере приложения задаёт цвет фона элемента на основе связанного с данными цвета или цвета по умолчанию (lightgray). Она также задаёт пользовательское свойство элемента (customProperty) со значением true без какой-либо причины, кроме демонстрации такой возможности.
import {Directive, inject, input} from '@angular/core';
/**
* Set backgroundColor for the attached element to highlight color
* and set the element's customProperty attribute to true
*/
@Directive({
selector: '[highlight]',
host: {
'[style.backgroundColor]': 'bgColor() || defaultColor',
},
})
export class Highlight {
readonly defaultColor = 'rgb(211, 211, 211)'; // lightgray
readonly bgColor = input('', {alias: 'highlight'});
}
Она используется в разных местах приложения, возможно, проще всего — в компоненте About:
@Component({
imports: [Twain, Highlight],
template: `
<h2 highlight="skyblue">About</h2>
<h3>Quote of the day:</h3>
<twain-quote />
`,
})
export class About {}
Для тестирования конкретного использования директивы Highlight в компоненте About достаточно применить методы, рассмотренные в разделе «Тестирование вложенных компонентов» раздела Сценарии тестирования компонентов.
let fixture: ComponentFixture<About>;
beforeEach(async () => {
TestBed.configureTestingModule({
providers: [TwainService, UserService],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
});
fixture = TestBed.createComponent(About);
await fixture.whenStable();
});
it('should have skyblue <h2>', () => {
const h2: HTMLElement = fixture.nativeElement.querySelector('h2');
const bgColor = h2.style.backgroundColor;
expect(bgColor).toBe('skyblue');
});
Однако тестирование одного сценария использования вряд ли позволит изучить весь спектр возможностей директивы. Поиск и тестирование всех компонентов, использующих эту директиву, — утомительная и ненадёжная задача, которая вряд ли обеспечит полное покрытие.
Тесты только класса могут быть полезны, но директивы атрибутов, подобные этой, обычно изменяют DOM. Изолированные модульные тесты не затрагивают DOM и поэтому не позволяют уверенно судить об эффективности директивы.
Лучше создать искусственный тестовый компонент, демонстрирующий все способы применения директивы.
@Component({
imports: [Highlight],
template: `
<h2 highlight="yellow">Something Yellow</h2>
<h2 highlight>The Default (Gray)</h2>
<h2>No Highlight</h2>
<input #box [highlight]="box.value" value="cyan" />
`,
})
class Test {}
ПОЛЕЗНО: В сценарии <input> привязывает Highlight к названию цвета, введённому в поле. Начальное значение — слово «cyan», которое должно стать цветом фона поля ввода.
Вот несколько тестов этого компонента:
let fixture: ComponentFixture<Test>;
let des: DebugElement[]; // the three elements w/ the directive
beforeEach(async () => {
fixture = TestBed.createComponent(Test);
await fixture.whenStable();
// all elements with an attached Highlight
des = fixture.debugElement.queryAll(By.directive(Highlight));
});
// color tests
it('should have three highlighted elements', () => {
expect(des.length).toBe(3);
});
it('should color 1st <h2> background "yellow"', () => {
const bgColor = des[0].nativeElement.style.backgroundColor;
expect(bgColor).toBe('yellow');
});
it('should color 2nd <h2> background w/ default color', () => {
const dir = des[1].injector.get(Highlight);
const bgColor = des[1].nativeElement.style.backgroundColor;
expect(bgColor).toBe(dir.defaultColor);
});
it('should bind <input> background to value color', async () => {
// easier to work with nativeElement
const input = des[2].nativeElement as HTMLInputElement;
expect(input.style.backgroundColor, 'initial backgroundColor').toBe('cyan');
input.value = 'green';
// Dispatch a DOM event so that Angular responds to the input value change.
input.dispatchEvent(new Event('input'));
await fixture.whenStable();
expect(input.style.backgroundColor, 'changed backgroundColor').toBe('green');
});
it('bare <h2> should not have a backgroundColor', () => {
// the h2 without the Highlight directive
const bareH2 = fixture.debugElement.query(By.css('h2:not([highlight])'));
expect(bareH2.styles.backgroundColor).toBeUndefined();
});
Стоит отметить несколько приёмов:
-
Предикат
By.directive— отличный способ получить элементы с этой директивой, когда типы элементов неизвестны. -
Псевдокласс
:notвBy.css('h2:not([highlight])')помогает найти элементы<h2>, у которых нет этой директивы.By.css('*:not([highlight])')находит любой элемент без этой директивы. -
DebugElement.stylesобеспечивает доступ к стилям элементов даже при отсутствии настоящего браузера благодаря абстракцииDebugElement. Но можете использоватьnativeElement, если это кажется проще или понятнее, чем абстракция. -
Angular добавляет директиву в инжектор элемента, к которому она применена. В тесте цвета по умолчанию используется инжектор второго
<h2>, чтобы получить его экземплярHighlightи егоdefaultColor. -
DebugElement.propertiesобеспечивает доступ к искусственному пользовательскому свойству, заданному директивой.
Super-powered by Google ©2010–2025.
Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
https://angular.dev/guide/testing/attribute-directives