Spec-Zone.ru › Angular

Тестирование директив атрибутов

Директива атрибута изменяет поведение элемента, компонента или другой директивы. Её название отражает способ применения директивы: в виде атрибута элемента-хоста.

Тестирование директивы 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 {}
HighlightDirective spec in action

ПОЛЕЗНО: В сценарии <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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API