как протестировать внедрение сценария в угловой ДОКУМЕНТ

#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, в любом случае мне нужно слушать загрузку скрипта независимо от используемого метода.