#angular #unit-testing #jestjs
Вопрос:
У меня есть угловая служба, которая вводит тег сценария в документ и возвращает обещание loaded
или completed
событие
@Injectable()
export class LoadService {
constructor(@Inject(DOCUMENT) private document: any) {}
load(
src: string
): Promise<void> {
return new Promise((resolve, reject) => {
let el = this.document.createElement('script');
el.setAttribute('src', src);
el.setAttribute('async', true);
// non of the following events emits
el.addEventListener('load', () => {
console.log('load');
resolve();
});
el.addEventListener('loaded', () => {
console.log('loaded');
resolve();
});
el.addEventListener('complete', () => {
console.log('complete');
resolve();
});
el.addEventListener('readystatechange', () => {
console.log('readystatechange');
if (
el.readyState === 'complete' ||
el.readyState === 'loaded' ||
el.readyState === 4
) {
console.log(`readystatechange: ${el.readyState}`);
resolve();
}
});
el.addEventListener('error', (err: any) => reject(err));
this.document.getElementsByTagName('head')[0].appendChild(el);
// just for testing
console.log('[load]', {
el,
onload: el.onload, //undefined
doc: this.document,
head: this.document.getElementsByTagName('head')[0],
// headOuterHTML: <head><script src=".." /></head>
headOuterHTML: this.document.getElementsByTagName('head')[0].outerHTML,
readyState: el.readyState, //undefined
onreadystatechange: el.onreadystatechange, //undefined
onError: el.onError, //undefined
});
});
}
}
теперь я хочу проверить, что служба создала и внедрила скрипт (т. е. обещание выполнено).
/**
* @jest-environment jsdom
*/
import { test, expect, afterAll, beforeAll, jest } from '@jest/globals';
import { TestBed } from '@angular/core/testing';
import { LoadService } from './load-scripts.service';
import { DOCUMENT } from '@angular/common';
// import 'zone.js/dist/zone';
let service: LoadService;
beforeAll(() => {
TestBed.configureTestingModule({
providers: [
NgxToolsLoadService
],
});
service = TestBed.inject(LoadService);
});
// success
test('service should be created', () => {
expect(service).toBeTruthy();
});
// fails due to timeout, because the events never fire
test('the script should be loaded', () => {
return service
.load('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js').resolves()
});
Комментарии:
1. Не рекомендуется напрямую изменять DOM, Почему бы не коснуться DOM с помощью сервиса
2. в реальном коде я использую RndererFactory2, в любом случае мне нужно слушать загрузку скрипта независимо от используемого метода.