ionic 2
中的测试套件尚未准备就绪。所以我使用这个tutorial进行测试。这主要使用angular 2
测试套件。这是我的test.ts
declare var __karma__: any;
declare var require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = function (): void { /* no op */};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
);
// Then we find all the tests.
const context: any = require.context('./', true, /\.spec\.ts/);
// And load the modules.
context.keys().map(context);
// Finally, start Karma to run the tests.
__karma__.start();
export class TestUtils {
public static beforeEachCompiler(components: Array<any>): Promise<{fixture: any, instance: any}> {
return TestUtils.configureIonicTestingModule(components)
.compileComponents().then(() => {
let fixture: any = TestBed.createComponent(components[0]);
return {
fixture: fixture,
instance: fixture.debugElement.componentInstance,
};
});
}
public static configureIonicTestingModule(components: Array<any>): typeof TestBed {
return TestBed.configureTestingModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [
...components
],
providers: [
NavController,LoadingController,App, Form, Keyboard, DomController, MenuController,
{ provide: Bookemon, useClass: BookMock},
{ provide: Authentication, useClass: AuthMock},
{provide: Storage, useClass: StorageMock},
{provide: Config, useClass: ConfigMock},
{provide: Platform, useClass: PlatformMock},
{provide: Events, useClass: Eventsmock}
],
imports: [
FormsModule,
IonicModule,
ReactiveFormsModule,
SwingModule
],
});
}
我正在尝试测试我的tab.ts
组件。
tab.ts
@Component({
selector: 'page-tabs',
templateUrl: 'tabs.html'
})
export class TabsPage {
user: any;
tab1Root: any = UserHuntsPage;
tab2Root: any = HomePage;
tab3Root: any = FeedPage;
constructor(public navCtrl: NavController , public auth: Authentication ,public events: Events) {
}
ngOnInit(){
this.events.subscribe('logout-user' , () => {
this.navCtrl.setRoot(WelcomePage);
})
}
}
以下是tab.pec.ts
let fixture: ComponentFixture<TabsPage> = null;
let instance: any = null;
describe('Tabs component',()=>{
beforeEach(async(() => TestUtils.beforeEachCompiler([TabsPage]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
})));
it('initialises', () => {
expect(1).toBeTruthy();
});
})
当我运行测试时,我收到此错误,
Error: No provider for DeepLinker!
at NoProviderError.BaseError [as constructor] (webpack:///~/@angular/core/src/facade/errors.js:24:0 <- src/test.ts:8542:34)
at NoProviderError.AbstractProviderError [as constructor] (webpack:///~/@angular/core/src/di/reflective_errors.js:41:0 <- src/test.ts:72995:16)
at new NoProviderError (webpack:///~/@angular/core/src/di/reflective_errors.js:72:0 <- src/test.ts:73026:16)
at ReflectiveInjector_._throwOrNull (webpack:///~/@angular/core/src/di/reflective_injector.js:758:0 <- src/test.ts:119137:19)
at ReflectiveInjector_._getByKeyDefault (webpack:///~/@angular/core/src/di/reflective_injector.js:786:0 <- src/test.ts:119165:25)
at ReflectiveInjector_._getByKey (webpack:///~/@angular/core/src/di/reflective_injector.js:749:0 <- src/test.ts:119128:25)
at ReflectiveInjector_.get (webpack:///~/@angular/core/src/di/reflective_injector.js:558:0 <- src/test.ts:118937:21)
at TestBed.get (webpack:///~/@angular/core/bundles/core-testing.umd.js:814:0 <- src/test.ts:39277:67)
at CompiledTemplate.proxyViewClass.AppView.injectorGet (webpack:///~/@angular/core/src/linker/view.js:109:0 <- src/test.ts:119679:45)
at CompiledTemplate.proxyViewClass.DebugAppView.injectorGet (webpack:///~/@angular/core/src/linker/view.js:351:0 <- src/test.ts:119921:49)
Error: Uncaught (in promise): Error: Error in ./TabsPage class TabsPage - inline template:0:0 caused by: No provider for DeepLinker!
at resolvePromise (webpack:///~/zone.js/dist/zone.js:468:0 <- src/test.ts:141307:31)
at resolvePromise (webpack:///~/zone.js/dist/zone.js:453:0 <- src/test.ts:141292:17)
at webpack:///~/zone.js/dist/zone.js:502:0 <- src/test.ts:141341:17
at ZoneDelegate.invokeTask (webpack:///~/zone.js/dist/zone.js:265:0 <- src/test.ts:141104:35)
at ProxyZoneSpec.onInvokeTask (webpack:///~/zone.js/dist/proxy.js:103:0 <- src/test.ts:110667:39)
at ZoneDelegate.invokeTask (webpack:///~/zone.js/dist/zone.js:264:0 <- src/test.ts:141103:40)
at Zone.runTask (webpack:///~/zone.js/dist/zone.js:154:0 <- src/test.ts:140993:47)
at drainMicroTaskQueue (webpack:///~/zone.js/dist/zone.js:401:0 <- src/test.ts:141240:35)
我的应用中没有使用DeepLinker
。我认为它可能是我的提供者中某些东西的依赖。我花了很多时间在这上面,我不明白为什么会这样。任何帮助将不胜感激。
修改
我在DeepLinker
中添加了providers
,但又出现了另一个错误,
Failed: Can't resolve all parameters for DeepLinker: (?, ?, ?).
Error: Can't resolve all parameters for DeepLinker: (?, ?, ?).
at CompileMetadataResolver._getDependenciesMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:623:0 <- src/test.ts:50686:19)
at CompileMetadataResolver._getTypeMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:517:0 <- src/test.ts:50580:26)
at webpack:///~/@angular/compiler/src/metadata_resolver.js:667:0 <- src/test.ts:50730:41
at Array.forEach (native)
at CompileMetadataResolver._getProvidersMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:647:0 <- src/test.ts:50710:19)
at CompileMetadataResolver._loadNgModuleMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:430:0 <- src/test.ts:50493:50)
at CompileMetadataResolver.loadNgModuleMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:313:0 <- src/test.ts:50376:29)
at RuntimeCompiler._loadModules (webpack:///~/@angular/compiler/src/runtime_compiler.js:99:0 <- src/test.ts:69258:41)
at RuntimeCompiler._compileModuleAndAllComponents (webpack:///~/@angular/compiler/src/runtime_compiler.js:83:0 <- src/test.ts:69242:35)
at RuntimeCompiler.compileModuleAndAllComponentsAsync (webpack:///~/@angular/compiler/src/runtime_compiler.js:65:0 <- src/test.ts:69224:21)
修改
将提供商添加为{ provide: DeepLinker, useValue: {} }
会导致新错误,
TypeError: this.parent.registerChildNav is not a function
at new Tabs (webpack:///~/ionic-angular/components/tabs/tabs.js:173:0 <- src/test.ts:46470:25)
at new Wrapper_Tabs (/IonicModule/Tabs/wrapper.ngfactory.js:7:18)
at CompiledTemplate.proxyViewClass.View_TabsPage0.createInternal (/DynamicTestModule/TabsPage/component.ngfactory.js:27:20)
at CompiledTemplate.proxyViewClass.AppView.create (webpack:///~/@angular/core/src/linker/view.js:74:0 <- src/test.ts:119644:21)
at CompiledTemplate.proxyViewClass.DebugAppView.create (webpack:///~/@angular/core/src/linker/view.js:330:0 <- src/test.ts:119900:44)
at CompiledTemplate.proxyViewClass.View_TabsPage_Host0.createInternal (/DynamicTestModule/TabsPage/host.ngfactory.js:16:19)
at CompiledTemplate.proxyViewClass.AppView.createHostView (webpack:///~/@angular/core/src/linker/view.js:81:0 <- src/test.ts:119651:21)
at CompiledTemplate.proxyViewClass.DebugAppView.createHostView (webpack:///~/@angular/core/src/linker/view.js:341:0 <- src/test.ts:119911:52)
at ComponentFactory.create (webpack:///~/@angular/core/src/linker/component_factory.js:154:0 <- src/test.ts:54276:25)
at initComponent (webpack:///~/@angular/core/bundles/core-testing.umd.js:852:0 <- src/test.ts:39321:53)
Error: Uncaught (in promise): Error: Error in ./TabsPage class TabsPage - inline template:0:0 caused by: this.parent.registerChildNav is not a function
at resolvePromise (webpack:///~/zone.js/dist/zone.js:468:0 <- src/test.ts:141416:31)
at resolvePromise (webpack:///~/zone.js/dist/zone.js:453:0 <- src/test.ts:141401:17)
at webpack:///~/zone.js/dist/zone.js:502:0 <- src/test.ts:141450:17
at ZoneDelegate.invokeTask (webpack:///~/zone.js/dist/zone.js:265:0 <- src/test.ts:141213:35)
at ProxyZoneSpec.onInvokeTask (webpack:///~/zone.js/dist/proxy.js:103:0 <- src/test.ts:110667:39)
at ZoneDelegate.invokeTask (webpack:///~/zone.js/dist/zone.js:264:0 <- src/test.ts:141212:40)
at Zone.runTask (webpack:///~/zone.js/dist/zone.js:154:0 <- src/test.ts:141102:47)
at drainMicroTaskQueue (webpack:///~/zone.js/dist/zone.js:401:0 <- src/test.ts:141349:35)
答案 0 :(得分:4)
我使用离子标签启动器模板遇到与OP相同的问题。我设法通过结合这里的建议和单元测试教程提供的mocks.ts中的示例来完成单元测试。
首先,我通过向mocks.ts:
添加一个模拟类来模拟DeepLinkerexport class DeepLinkerMock {
}
然后在test.ts中的TestBed.configureTestingModule中将其添加为提供程序:
{provide: DeepLinker, useClass: DeepLinkerMock},
您还需要为其添加导入,以及test.ts中NavMock的导入:
import {ConfigMock, PlatformMock, NavMock, DeepLinkerMock} from './mocks';
此时你的测试将失败,而this.parent.registerChildNav不是一个函数。我在ionic-angular(文件nav-controller-base.js)中查找了registerChildNav方法的签名。您需要在mocks.ts中的NavMock类中为此方法添加存根:
export class NavMock {
...
public registerChildNav(nav: any): void {
return ;
}
}
现在你的测试将失败,没有TransitionController的提供者!添加该提供程序可以轻松解决此问题。此时我的提供者看起来像这样:
providers: [
App, Form, Keyboard, DomController, MenuController, GestureController, TransitionController,
{provide: Platform, useClass: PlatformMock},
{provide: Config, useClass: ConfigMock},
{provide: DeepLinker, useClass: DeepLinkerMock},
{provide: NavController, useClass: NavMock}],
注意我将NavController提供程序替换为模拟的提供程序 - 它存在于教程代码中但未被引用。 FYI GestureController也不在原始教程代码中 - 它是选项卡启动项目中其他原始四个页面之一所必需的。
不要忘记为TransitionController(和GestureController)添加导入。我的编辑(Webstorm)提出了三种选择。我选择了这个 - 不确定它是否正确:
import {TransitionController} from "ionic-angular/transitions/transition-controller";
此时,我在教程中建议的基本表单有四个单元测试,用于选项卡启动器中的四个页面。这是tabs.spec.ts:
import {Component} from "@angular/core";
import {HomePage} from "../home/home";
import {AboutPage} from "../about/about";
import {ContactPage} from "../contact/contact";
@Component({
templateUrl: './tabs.html'
})
export class TabsPage {
// this tells the tabs component which Pages
// should be each tab's root Page
tab1Root: any = HomePage;
tab2Root: any = AboutPage;
tab3Root: any = ContactPage;
constructor() {
}
}
我想我会遵循这种模式,因为我继续使用未被教程编写者嘲笑的更多框架。
答案 1 :(得分:2)
你是对的,它可能是其中一个组件的依赖关系。您是否尝试过将DeepLinker提供给TestBed,如下所示:
TestBed.configureTestingModule({
...
providers: [
DeepLinker,
... // the usual stuff
如果真的不需要,你也可以轻松地删除它的功能:
TestBed.configureTestingModule({
...
providers: [
{ provide: DeepLinker, useValue: {} },
... // the usual stuff
编辑到最后一个错误:
以这种方式提供DeepLinker成功实例化并使用空对象覆盖实际的DeepLinker实现。但是,应用程序的某些部分需要缺少registerChildNav
方法。您最好的选择是在覆盖原始DeepLinker实现的对象上创建此方法。
let deepLinkerStub = {
registerChildNav: () => {}
};
TestBed.configureTestingModule({
...
providers: [
{ provide: DeepLinker, useValue: deepLinkerStub },
... // the usual stuff
检查DeepLinker的原始实现,以查看原始registerChildNav的工作原理,并为此测试创建存根方法。
答案 2 :(得分:0)
在test.ts
providers: [
{provide: DeepLinker, useClass: DeepLinkerMock},
{provide: NavController, useClass: NavMock}
...config.providers
],
以及更新mock.ts添加两个类DeepLinkerMock
&amp;&amp; NavMock
export class DeepLinkerMock{
}
export class NavMock {
public length(): number {
return 1; }
public push(): any {
return new Promise(function(resolve: Function): void {
resolve();
}); }
public getActive(): any {
return {
'instance': {
'model': 'something',
},
}; }
public setRoot(): any {
return true; }
public pop(): any {
return new Promise(function(resolve: Function): void {
resolve();
}); }
public registerChildNav(): any {
return new Promise(function(resolve: Function): void {
resolve();
}); }
public unregisterChildNav(): any {
return new Promise(function(resolve: Function): void {
resolve();
}); }
public popToRoot(): any {
return true; }
public canGoBack(): any {
return true; } }