Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error: No provider for DeepLinker while unit testing components

Tags:

angular

ionic2

Testing suite is still not ready in ionic 2. So I am using this tutorial for the test. This essentially uses angular 2 testing suite . Here is my 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
      ],
    });
  }

I am trying to test my tab.ts component.

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);
     })
  }
}

Here is 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();
  });
})

When i run the test I get this error,

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)

I have not used DeepLinker anywhere in my app. I am thinking it might be a dependency of something in my providers. I have spent a lot of time on this and I cant understand why this is happening. Any help would be appreciated.

Edit

I added DeepLinkerin the providers but that gives another error,

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)

edit

adding providers as { provide: DeepLinker, useValue: {} } results in new error,

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)
like image 221
raj Avatar asked Sep 05 '26 09:09

raj


1 Answers

I was having the same problem as the OP using the ionic tabs starter template. I managed to get the unit tests working by combining the suggestions here with following the examples in the mocks.ts provided by the unit test tutorial.

First I mocked the DeepLinker by adding a mocked class to the mocks.ts:

export class DeepLinkerMock {
}

Then add it as a provider in TestBed.configureTestingModule in test.ts:

{provide: DeepLinker, useClass: DeepLinkerMock},

You will also need to add an import for it, as well as an import for the NavMock in test.ts:

import {ConfigMock, PlatformMock, NavMock, DeepLinkerMock} from './mocks';

At this point your test will fail with this.parent.registerChildNav is not a function. I looked up the signature of the registerChildNav method in ionic-angular (file nav-controller-base.js). You need to add a stub for this method in the NavMock class in mocks.ts:

export class NavMock {
    ...
    public registerChildNav(nav: any): void {
        return ;
    }
}

Now your test will fail with No provider for TransitionController! This is easily remedied by adding that provider. At this point my providers looks like this:

 providers: [
    App, Form, Keyboard, DomController, MenuController, GestureController, TransitionController,
    {provide: Platform, useClass: PlatformMock},
    {provide: Config, useClass: ConfigMock},
    {provide: DeepLinker, useClass: DeepLinkerMock},
    {provide: NavController, useClass: NavMock}],

Notice I replaced the NavController provider with the mocked one - which existed in the tutorial code but was not referenced. FYI GestureController was not in the original tutorial code either - it is required by one of the other original four pages in the tabs starter project.

Do not forget to add an import for the TransitionController (and GestureController). My editor (Webstorm) suggested three choices. I chose this one - not sure if it is correct:

import {TransitionController} from "ionic-angular/transitions/transition-controller";

At this point, I have four unit tests of the basic form suggested in the tutorial working for the four pages in the tabs starter. This is the 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() {

    }
}

I imagine I will follow this pattern as I continue to make use of more pieces of the framework which were not mocked out by the tutorial writer.

like image 157
Milton Avatar answered Sep 08 '26 06:09

Milton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!