Angular 1.x/2 Гибрид, тесты кармы не загружают приложение ng1

В настоящее время у меня есть гибридное приложение Angular (2.4.9 и 1.5.0) с помощью angular -cli. В настоящее время при запуске нашего приложения мы можем правильно загружать приложение 1.5:

// main.ts
import ...

platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
  angular.element(document).ready(() => { 
    const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
    upgrade.bootstrap(document.body, ['myApp'], {strictDi: true});
  });
});

Однако в нашем test.ts файле:

// test.ts
// This file is required by karma.conf.js and loads recursively all the .spec and framework files

import ...;

declare var __karma__: any;
declare var require: any;

__karma__.loaded = function () {};

getTestBed().initTestEnvironment(
  BrowserDynamicTestingModule,
  // I'm assuming that I need to call 'boostrapModule()' somehow here...
  platformBrowserDynamicTesting() 
);

const context = require.context('./', true, /\.spec\.ts$/);

context.keys().map(context);

__karma__.start();

Я не совсем уверен, как загружать наше приложение 1.5 в тестовую среду, все, что я получил, это Module 'myApp' is not available!, и мои навыки Google не смогли найти пример.

Ответ 1

Я надеялся, что щедрость, которую я добавил вчера вечером, означала бы, что я смогу войти сегодня утром в хорошее решение, предложенное для меня. Увы, это не так. Поэтому вместо этого я провел день, путешествуя по многим SO-ответам и вопросам github, чтобы заставить его работать. Мне жаль, что я не отслеживал все, что помогло мне кредитовать их, но вот мое решение. Это, вероятно, не идеально, но он работает до сих пор, поэтому я надеюсь, что это хорошее начало.

Эта проблема github указывает, что downgradeComponent пока не работает, поэтому я пошел с тем, что, как я полагаю, является более старой техникой используя UpgradeAdapter. Обратите внимание, что этот метод не использует initTestEnvironment. Вот соответствующие фрагменты, с некоторыми пояснениями ниже:

// downgrade.ts:
export const componentsToDowngrade = {
    heroDetail: HeroDetailComponent,
    ...
};
export function downgradeForApp() {
    forOwn(componentsToDowngrade, (component, name) => {
        app.directive(name!, downgradeComponent({ component }));
    });
}


// main.ts:
downgradeForApp();
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).then((platformRef) => {
    ...
});

// test.ts:
require("../src/polyfills.ts");
require("zone.js/dist/proxy");
require('zone.js/dist/sync-test');
require("zone.js/dist/mocha-patch");

// test-helper.ts
let upgradeAdapterRef: UpgradeAdapterRef;
const upgradeAdapter = new UpgradeAdapter(AppModule);
forEach(componentsToDowngrade, (component, selectorName) => {
    angular.module("app").directive(
        selectorName!,
        upgradeAdapter.downgradeNg2Component(component) as any,
    );
});
export function useAdaptedModule() {
    beforeEach(() => {
        upgradeAdapterRef = upgradeAdapter.registerForNg1Tests(["app"]);
    });
}
export function it(expectation: string, callback: () => void) {
    test(expectation, (done) => {
        inject(() => { }); // triggers some kind of needed initialization
        upgradeAdapterRef.ready(() => {
            try {
                callback();
                done();
            } catch (ex) { done(ex); }
        });
    });
}


// hero-detail.component.spec.ts
import { it, useAdaptedModule } from "test-helpers/sd-app-helpers";
describe("", () => {
    useAdaptedModule();
    it("behaves as expected", () => { ... });
});

Несколько основных моментов этого кода:

  • Я отказываюсь от компонентов по-разному для тестов, чем для приложения, поэтому я сделал DRY-список из них в downgrade.ts
  • Я снижаю компоненты основного приложения из main.ts, вызывая downgradeForApp(), как показано выше (используется с AOT для производственного пакета), а также main-jit.ts, не показанный выше (используется для разработки)
  • Я показал импорт, который мне нужно добавить, чтобы начать интеграцию компонентов Angular в мои тесты AngularJS. Возможно, вам понадобится больше/разные, например, о том, являются ли ваши тесты асинхронными, или вы используете Jasmine вместо Mocha.
  • В начале каждого теста, который должен использовать пониженные компоненты, я "загружаю" вещи с помощью useAdaptedModule() вместо beforeEach(angular.mock.module("app"));
  • Я импортирую альтернативный it из моих помощников, который обертывает it, предоставленный Mocha. Ни один из моих тестов не асинхронен; если у вас есть такие, которые могут потребовать настройки. Я не знаю, как это может понадобиться для Jasmine.

Предостережение. Создание экземпляра компонента должно происходить в обратном вызове it, так что это происходит в upgradeAdapterRef.ready(...). Попытка сделать это в beforeEach слишком скоро.