Как издеваться над угловым внешним объектом Javascript

У меня есть приложение angular, единственной целью которого является создание @angular / elements (без index.html, без app.component и т. Д.).

Эти элементы используются в приложении.NET Mvc, которое предоставляет два типа вещей, которые я пытаюсь имитировать в своих модульных тестах:

1 - Внешние библиотеки

Например, JQuery, lodash и т. Д.

2 - Клиентская платформа "foo"

Внутри представления.NET MVC, которое включает мои веб-элементы, приложение MVC создает объект с именем foo. Этот объект не является модулем ES6. Он создается вручную с помощью красивого foo = new Foo({ someOptionsGeneratedFromServerSide});

Оба случая используются внутри моих веб-элементов. Например, компонент будет использовать функцию foo.displayAlert("С сообщением"). Единственное решение, которое я нашел, чтобы заставить мое приложение angular соответствовать этому, - это добавить следующее:

// tslint:disable-next-line: max-line-length no-reference
/// <reference path='path/to/the/definition.d.ts' />

Я знаю, что это не совсем ортодоксально.

Приложение Angular работает нормально, пока я не попробую выполнить модульное тестирование. Примечание: он не может работать в одиночку (ng serve, как и ожидалось, бесполезен).

Пример

it('should render title', () => {
  const fixture = TestBed.createComponent(AppComponent);
  fixture.detectChanges();
  const compiled = fixture.nativeElement;
  expect(compiled.querySelector('.content span').textContent).toContain('ng-jest app is running!');
});

Для этого компонента / крючка:

ngOnInit() {
  foo.displayAlert('With a message');
}

Произойдет сбой со следующим (вполне ожидаемым) сообщением:

AppComponent › should render title
ReferenceError: foo is not defined

Я попытался явно издеваться над объектом перед тестом:

  let foo: any;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        AppComponent
      ],
    }).compileComponents();
    foo = {
      displayAlert: Function
    };
  }));

Пока не повезло. Я делал много попыток насмехаться над этим объектом внутри x.spect.ts, но безрезультатно.

Я попытался создать другое приложение Angular с index.html, которое включает все ресурсы, такие как представление MVC, но это не удалось.

Заключительные примечания

Для сторонних разработчиков, таких как JQuery / lodash, я не хочу добавлять их в свой проект Angular, например:npm i -D lodashпоскольку я не хочу, чтобы они были включены в мой файл vendor.js. Эти библиотеки предоставляются приложением.Net Mvc, и это нормально. Это также относится к объекту foo. Наконец, я попробовал с (Jest) и без (Karma) безголовый браузер для тестов.

Любая помощь могла бы быть полезна!

Изменить 27/03/2020

Пожалуйста спаси меня!

Изменить 28/03/2020

Пробовал jasmine.createSpyObject & spyOn, тоже не повезло:(

1 ответ

Решение

Сложная настройка, вы не упростите себе задачу.

Однако, похоже, вам просто нужно подделать fooв качестве глобальной переменной, поскольку глобальная область видимости - это то место, где ваш компонент ожидает, что переменная будет. Когда вы заявляетеlet foo внутри модуля ECMAScript вы создаете переменную, привязанную к этому файлу, к которому ваш компонент не может получить доступ.

beforeEach(() => {
  window.foo = {
    displayAlert: () => {},
  };
});

Это, вероятно, заставит вас бороться с TypeScript. Быстрое исправление - это

beforeEach(() => {
  (window as any).foo = {
    displayAlert: () => {},
  };
});
Другие вопросы по тегам