Тестирование @HostListening ('error') на директиве Angular 7 - PullRequest
0 голосов
/ 21 марта 2019

У нас есть хранилище логотипов, которые мы можем искать по идентификатору, но есть несколько случаев, когда они отсутствуют, и вместо этого нам нужно показать логотип «по умолчанию».Я сделал угловую директиву, чтобы немного облегчить этот процесс.Он используется следующим образом:

<img [appLogoFromId]="item.id"/>

А вот рабочая директива

import { Directive, Input, ElementRef, HostListener } from '@angular/core';

@Directive({
    selector: '[appLogoFromId]'
})
export class LogoFromIdDirective {
    private static readonly baseUrl: string = 'https://our-website.com/sitelogos/';
    private static readonly fallbackImgUrl: string = LogoFromIdDirective.baseUrl + 'default.svg';

    @Input() set appLogoFromId(value: string | number) {
        this.nativeEl.src = LogoFromIdDirective.baseUrl + value + '.jpg';
    }

    private readonly nativeEl: HTMLImageElement;
    private errCount: number = 0;

    constructor(private elem: ElementRef) {
        this.nativeEl = this.elem.nativeElement;

        //This directive only works on <img> elements, so throw an error otherwise
        const elTag = this.nativeEl.tagName.toLowerCase();
        if (elTag !== 'img') {
            throw Error(`The "appLogoFromId" directive may only be used on "<img>" elements, but this is a "<${elTag}>" element!`);
        }
    }

    @HostListener('error') onError(): void {
        //404 error on image path, so we instead load this fallback image
        //but if that fallback image ever goes away we don't want to be in a loop here,
        //so we ned to keep track of how many errors we've encountered
        if (this.errCount < 2) {
            this.nativeEl.src = LogoFromIdDirective.fallbackImgUrl;
        }
        this.errCount++;
    }
}

Мой вопрос: Как мне проверить часть @HostListener('error') этой директивы?

У меня есть этот тест, но он не проходит.что мне нужно делать по-другому?

it('should update the img element src attribute for an invalid image', () => {
    component.bankId = 'foo';
    fixture.detectChanges();
    expect(nativeEl.src).toBe('https://our-website.com/sitelogos/default.svg');
});

сообщение об ошибке:

Expected 'https://our-website.com/sitelogos/foo.jpg' to be 'https://our-website.com/sitelogos/default.svg'.

Для полноты, вот весь мой файл спецификации для этой директивы

import { LogoFromIdDirective } from './logo-from-id.directive';

import {ComponentFixture, TestBed } from '@angular/core/testing';
import { Component, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';


@Component({
    template: `<img [appLogoFromId]="theId" />`
})
class TestLogoFromIdOnImgComponent {
    theId: number | string = 5;
}

@Component({
    template: `<div [appLogoFromId]="theId" />`
})
class TestLogoFromIdOnNonImgComponent {
    theId: number | string = 5;
}

describe('Directive: [appLogoFromId]', () => {
    describe('On an `<img>` element', () => {
        let component: TestLogoFromIdOnImgComponent;
        let fixture: ComponentFixture<TestLogoFromIdOnImgComponent>;
        let inputEl: DebugElement;
        let nativeEl: HTMLInputElement;

        beforeEach(() => {
            TestBed.configureTestingModule({
            declarations: [TestLogoFromIdOnImgComponent, LogoFromIdDirective],
            schemas:      [ NO_ERRORS_SCHEMA ]
            });
            fixture = TestBed.createComponent(TestLogoFromIdOnImgComponent);
            component = fixture.componentInstance;
            inputEl = fixture.debugElement.query(By.css('img'));
            nativeEl = inputEl.nativeElement;
        });

        it('should set the img element src attribute for a valid image', () => {
            fixture.detectChanges();
            expect(nativeEl.src).toBe('https://our-website.com/sitelogos/5.jpg');
        });

        it('should update the img element src attribute for a valid image when using a number', () => {
            component.theId = 2852;
            fixture.detectChanges();
            expect(nativeEl.src).toBe('https://our-website.com/sitelogos/2852.jpg');
        });

        it('should update the img element src attribute for a valid image when using a string', () => {
            component.theId = '3278';
            fixture.detectChanges();
            expect(nativeEl.src).toBe('https://our-website.com/sitelogos/3278.jpg');
        });

        it('should update the img element src attribute for an invalid image', () => {
            component.theId = 'foo';
            fixture.detectChanges();
            expect(nativeEl.src).toBe('https://our-website.com/sitelogos/default.svg');
        });
    });

    describe('On a `<div>` element', () => {
        it('should throw an error', () => {
            TestBed.configureTestingModule({
                declarations: [TestLogoFromIdOnNonImgComponent, LogoFromIdDirective],
                schemas:      [ NO_ERRORS_SCHEMA ]
            });
            expect(() => TestBed.createComponent(TestLogoFromIdOnNonImgComponent)).toThrow();
        });
    });
});

Ответы [ 2 ]

0 голосов
/ 22 марта 2019

Я наконец-то нашел решение, которое работает!

it('should update the img element src attribute for an invalid image', () => {
    const spyError = spyOn(nativeEl, 'onerror' ).and.callThrough();
    component.bankId = 'foo';
    fixture.detectChanges();
    nativeEl.dispatchEvent(new Event('error'));
    expect(spyError).toHaveBeenCalled();
    expect(nativeEl.src).toBe('https://our-website.com/sitelogos/default_bank.svg');
});
0 голосов
/ 21 марта 2019

Примерно так должно работать:

inputEl.triggerEventHandler('error', null);
fixture.detectChanges();
expect(nativeEl.src).toBe('https://our-website.com/sitelogos/default.svg');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...