Я пытаюсь смоделировать объект DOM Image
по умолчанию для модульного тестирования службы Angular.
Сервис простой, он проверяет поддержку формата "webP":
import {Injectable} from '@angular/core';
import {Promise} from 'es6-promise';
import {environment} from '../../../../environments/environment';
@Injectable({
providedIn: 'root'
})
export class AppLoadService {
constructor() {
}
initializeApp(): Promise<any> {
return new Promise((resolve) => {
console.log(`initializeApp:: inside promise`);
if (typeof Image === 'undefined') {
console.log(`initializeApp:: Image undefined`);
resolve();
return;
}
const webP = new Image();
webP.onload = () => {
console.log(`initializeApp:: WebP support: true`);
environment.webP = true;
resolve();
};
webP.onerror = () => {
console.log(`initializeApp:: WebP support: false`);
resolve();
};
webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
});
}
}
Я нашел способ проверить поддержку webP (по умолчанию в chromium, где работает Karma) и способ проверить откат на Image undefined
.
Но я не могу найти способ проверить onerror
запасной вариант ...
Вот мой файл спецификаций:
import {TestBed} from '@angular/core/testing';
import {AppLoadService} from './app-load.service';
import {environment} from '../../../../environments/environment';
describe('AppLoadService', () => {
let service: AppLoadService;
const originalImage = Image;
beforeEach(() => TestBed.configureTestingModule({}));
beforeEach(() => {
service = TestBed.get(AppLoadService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should resolve with webP', (done) => {
const test = () => {
Image = originalImage;
service.initializeApp().then(() => {
expect(environment.webP).toBe(true);
done();
});
};
test();
});
it('should resolve without webP (A)', (done) => {
const test = () => {
Image = undefined;
service.initializeApp().then(() => {
expect(environment.webP).toBe(false);
done();
});
};
test();
});
it('should resolve without webP (B)', (done) => {
// How to force Image to throw "onerror" ?
const test = () => {
Image = originalImage;
service.initializeApp().then(() => {
expect(environment.webP).toBe(false);
done();
});
};
test();
});
});
Вопрос по should resolve without webP (B)
test, в конце файла ..
Кроме того, есть ли лучший способ проверить неопределенный объект Image или onload
callback?
Спасибо!
EDIT
Не могу заставить его работать так, как есть, поэтому я изменяю конструктор службы, чтобы обеспечить зависимость "Изображение".
constructor(@Inject('Image') image: typeof Image) {
this.image = image;
}
Нужно загрузить модуль так:
providers: [
AppLoadService,
// [...]
{provide: 'Image', useValue: Image},
]
И каждый resolve()
теперь включает в себя environment.webP
результат. В противном случае индивидуальный тест представляет собой настоящую боль, environment
случайным образом переписывается перед тестированием.
С простым макетом это работает так:
import {TestBed} from '@angular/core/testing';
import {AppLoadService} from './app-load.service';
class MockImageFail {
public onerror: Function;
private _src: string;
set src(src) {
this._src = src;
if (this.onerror) {
this.onerror();
}
}
}
describe('AppLoadService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{provide: 'Image', useValue: Image}]
});
});
it('should be created', () => {
const service = TestBed.get(AppLoadService);
expect(service).toBeTruthy();
});
it('should resolve with webP', (done) => {
const service = TestBed.get(AppLoadService);
service.initializeApp().then((supportWebP) => {
expect(supportWebP).toBe(true);
done();
});
});
it('should not resolve without webP (A)', (done) => {
TestBed.overrideProvider('Image', {useValue: undefined});
const service = TestBed.get(AppLoadService);
service.initializeApp().then((supportWebP) => {
expect(supportWebP).toBe(false);
done();
});
});
it('should not resolve without webP (B)', (done) => {
TestBed.overrideProvider('Image', {useValue: MockImageFail});
const service = TestBed.get(AppLoadService);
service.initializeApp().then((supportWebP) => {
expect(supportWebP).toBe(false);
done();
});
});
});
Я не очень доволен этим и уверен, что есть другой лучший способ: /