I am writing an angular 2 application and am using our UI team's library. The development of the application is going great, I can use all of their components easily by using an import statement like so. This is my app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { SohoComponentsModule } from '#infor/sohoxi-angular'; // This is the one in question.
import { AppComponent } from './app.component';
import { licenseGeneratorComponent } from './licenseGenerator.component';
import { emergencyLicenseComponent } from './tabs/emergency/emergencyLicense.component';
import { partnerLicenseComponent } from './tabs/partner/partnerLicense.component';
import { standardLicenseComponent } from './tabs/standard/standardLicense.component';
#NgModule({
declarations: [
AppComponent,
licenseGeneratorComponent,
emergencyLicenseComponent,
partnerLicenseComponent,
standardLicenseComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
SohoComponentsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
and here is one of my templates used within this app, the soho stuff is from this library:
<div class="row">
<div class="twelve columns">
<h1>License Generator</h1>
<div soho-tabs>
<ul soho-tab-list>
<li soho-tab><a soho-tab-title tabId='tabs-normal-emergency'>Emergency Licenses</a></li>
<li soho-tab><a soho-tab-title tabId='tabs-normal-partner'>Partner Licenses</a></li>
<li soho-tab><a soho-tab-title tabId='tabs-normal-standard'>Standard Licenses</a></li>
</ul>
<div soho-tab-panel tabId='tabs-normal-emergency'>
<emergency-license></emergency-license>
</div>
<div soho-tab-panel tabId='tabs-normal-partner'>
<partner-license></partner-license>
</div>
<div soho-tab-panel tabId='tabs-normal-standard'>
<standard-license></standard-license>
</div>
</div>
</div>
</div>
The application has been working just fine, no issues. But when there is an issue with my unit tests now. I had them working before with the first few unit tests but left it alone for a week or so and added more content and now the tests don't run properly.
When I run my tests I get the error
Unexpected value 'SohoComponentsModule' imported by the module 'DynamicTestModule'
My app.component.spec looks like this:
import { TestBed, async } from '#angular/core/testing';
import { FormsModule } from '#angular/forms';
import { AppComponent } from './app.component';
import { licenseGeneratorComponent } from './licenseGenerator.component';
import { emergencyLicenseComponent } from './tabs/emergency/emergencyLicense.component';
import { partnerLicenseComponent } from './tabs/partner/partnerLicense.component';
import { standardLicenseComponent } from './tabs/standard/standardLicense.component';
import { SohoComponentsModule } from '#infor/sohoxi-angular';
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
licenseGeneratorComponent,
emergencyLicenseComponent,
partnerLicenseComponent,
standardLicenseComponent,
],
imports: [
FormsModule,
SohoComponentsModule
],
});
});
it('should create the app', async(() => {
let fixture = TestBed.createComponent(AppComponent);
let app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app works!'`, async(() => {
let fixture = TestBed.createComponent(AppComponent);
let app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app works!');
}));
});
I am going in circles now though because if I remove the import statement in the test it throws these errors:
Can't bind to 'closeOnSelect' since it isn't a known property of 'select'. ("label required">Versions</label>
Please Help!
Keep in mind the application works just fine still, just the unit tests that are giving me issues. I've spent all day looking around for fixes but can't figure this out.
Please let me know if I need to post more of my files.
Thanks,
Chris
For some reason it was the angular library that was causing this issue.
I updated the version and the issue was fixed.
Related
In Ionic 2, how do I create a custom directive that uses Ionic components?
This answer doesn't work anymore.
import {IONIC_DIRECTIVES} from 'ionic-angular'
this also doesn't work. How can i create a custom component that uses Ionic components in Ionic 2, version 3.0.1?
If you stuck with this problem after using lazy loading you should do that like that:
Add IonicModule to 'imports' parameter of CustomComponentModule
Use ionic components in custom components' templates
Add CustomComponentModule to 'imports' parameter of your AnotherComponentModule where you want use that component (CustomComponentModule).
deletable.module.ts
import { NgModule } from '#angular/core';
import { DeletableItem } from './deletable';
import { IonicModule } from 'ionic-angular';
#NgModule({
declarations: [
DeletableItem
],
imports: [
IonicModule
],
exports: [
DeletableItem
]
})
export class DeletableModule {}
bill.html
<ion-content padding>
<ion-list>
<ion-item *ngFor="let bill of bills" (click)="openEdit(bill)">
<ion-label text-left>{{bill.name}}</ion-label>
<ion-label text-right>{{bill.amount}}</ion-label>
<deletableItem></deletableItem>
</ion-item>
</ion-list>
</ion-content>
bill.module.ts
import { NgModule } from '#angular/core';
import { IonicPageModule } from 'ionic-angular';
import { BillPage } from './bill';
import { DeletableModule } from './../../components/deletable/deletable.module'
#NgModule({
declarations: [
BillPage
],
imports: [
IonicPageModule.forChild(BillPage),
DeletableModule
],
exports: [
BillPage
]
})
export class BillModule {}
That's work for me.
Error Description
Angular version: 2.3.1
My unit test fails to create the component - I know this issue is related to the [routerLink] and [routerLinkActive] directives because removing them from the template allows the test to create the component.
TEMPLATE
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle" data-toggle="collapse" data-target="#iotahoe-top-navigation">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" [routerLink]="['/']">IoTahoe</a>
</div>
<div class="collapse navbar-collapse" id="iotahoe-top-navigation">
<ul *ngIf="isAuthenticated()" class="nav navbar-nav navbar-right">
<li [routerLinkActive]="['active']"><a [routerLink]="['/dashboard']">Dashboard</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/browse']">Browse</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/admin']">Admin</a></li>
<li [routerLinkActive]="['active']"><a (click)="onLogout()" style="cursor: pointer;">Logout</a></li>
</ul>
</div>
TYPESCRIPT
import { Component, OnInit } from '#angular/core';
import { AuthenticationService } from '../../authentication/authentication.service';
import { Router } from '#angular/router';
#Component({
moduleId: module.id.toString(),
selector: 'app-top-navbar',
templateUrl: './top-navbar.component.html',
styleUrls: ['./top-navbar.component.css']
})
export class TopNavbarComponent implements OnInit {
constructor(private authenticationService: AuthenticationService, private router: Router) { }
ngOnInit() {
}
isAuthenticated() {
return this.authenticationService.isLoggedIn;
}
onLogout() {
this.authenticationService.logout().subscribe(() => {
return this.router.navigate(['/login']);
});
}
}
TEST SPEC
/* tslint:disable:no-unused-variable */
import {async, ComponentFixture, TestBed, inject} from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import {DebugElement, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, Component} from '#angular/core';
import { RouterTestingModule } from '#angular/router/testing';
import { Location, CommonModule } from '#angular/common';
import { TopNavbarComponent } from './top-navbar.component';
import { AuthenticationService } from '../../authentication/authentication.service';
import { Router } from '#angular/router';
import {ReactiveFormsModule} from "#angular/forms";
#Component({
template: ''
})
class DummyComponent {
}
describe('TopNavbarComponent', () => {
let component: TopNavbarComponent;
let fixture: ComponentFixture<TopNavbarComponent>;
let authenticationService: AuthenticationService;
beforeEach(async(() => {
const authenticationServiceStub = {
isLoggedIn: false
};
const routerStub = {
navigate: jasmine.createSpy('navigate'),
navigateByUrl: jasmine.createSpy('navigateByUrl')
};
TestBed.configureTestingModule({
declarations: [ TopNavbarComponent, DummyComponent ],
imports:[CommonModule, ReactiveFormsModule, RouterTestingModule.withRoutes(
[
{ path: '/', component:DummyComponent },
{ path: '/login', component:DummyComponent },
{ path: '/dashboard', component:DummyComponent },
{ path: '/browse', component:DummyComponent },
{ path: '/admin', component:DummyComponent }
])],
providers: [
{ provide: AuthenticationService, useValue: authenticationServiceStub },
{ provide: Router, useValue: routerStub }
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TopNavbarComponent);
component = fixture.componentInstance;
authenticationService = TestBed.get(AuthenticationService);
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
ERROR
zone.js:155 Uncaught Error: Error in package:407:9:6 caused by: Cannot
read property 'root' of undefined
at ViewWrappedError.Error (native)
at ViewWrappedError.ZoneAwareError (localhost:9876/base/src/test.ts:133296:33)
at ViewWrappedError.BaseError [as constructor] (localhost:9876/base/src/test.ts:35630:16)
at ViewWrappedError.WrappedError [as constructor] (localhost:9876/base/src/test.ts:35695:16)
at new ViewWrappedError (localhost:9876/base/src/test.ts:68018:16)
at DebugAppView._rethrowWithContext (localhost:9876/base/src/test.ts:108242:23)
at DebugAppView.create (localhost:9876/base/src/test.ts:108142:18)
at DebugAppView.View_TopNavbarComponent_Host0.createInternal (/DynamicTestModule/TopNavbarComponent/host.ngfactory.js:16:19)
at DebugAppView.AppView.createHostView (localhost:9876/base/src/test.ts:107700:21)
at DebugAppView.createHostView (localhost:9876/base/src/test.ts:108156:52)
at ComponentFactory.create (localhost:9876/base/src/test.ts:49830:25)
at initComponent (localhost:9876/base/src/test.ts:6425:53)
at ZoneDelegate.invoke (localhost:9876/base/src/test.ts:132727:26)
at ProxyZoneSpec.onInvoke (localhost:9876/base/src/test.ts:95802:39)
at ZoneDelegate.invoke (localhost:9876/base/src/test.ts:132726:32)Zone.runTask #
zone.js:155ZoneTask.invoke # zone.js:345data.args.(anonymous function)
# zone.js:1376
The routerLink directives need a real router, but you are mocking it. A couple things I can see you doing:
If you don't plan to click the links during testing, then you can mock those directive to just make "noop" directives so the compiler doesn't complain. e.g.
#Directive({
selector: '[routerLink], [routerLinkActive]'
})
class DummyRouterLinkDirective {}
Then just add that to the declarations of the test module. With this you don't really need to configure the RouterTestingModule at all. You could probably get rid of that.
Also if you don't plan to click test, another option (without needing to create dummy directives is to just ignore the errors of missing directives:
schemas: [ NO_ERRORS_SCHEMA ]
You would add this to the test module configuration (as seen here). This might not be desirable in some cases, as it could also ignore errors that you actually want detected, which could lead to hard to debug tests.
If you would actually like to click the links and test routing, then you can use the real router. You can see an example of how you can test the navigation, using the Location, as seen in this post.
For me the solution with the non-mocked routing worked. But I found out that I also needed to add a
<router-outlet></router-outlet>
to the component using "routerlink active".
I am writing some tests for my Angular2 application according to the documentation but I have run into a problem which I can't seem to fix. I get the following error when trying to launch the spec runner:
Failed: This test module uses the component CategoriesComponent which is using a "templateUrl", but they were never compiled. Please call "TestBed.compileComponents" before your test.
I understand this is happening as I am using a seperate template file for the template within the component but I jhave tried multilpe solutions which don't seem to work.
Here is my component under test:
import { Component } from "#angular/core";
#Component({
selector: 'categories-component',
templateUrl: '/app/views/catalog/categories/categories-dashboard.html',
moduleId: module.id
})
export class CategoriesComponent {
title: 'Categories;
}
The categories-dashboard.html file:
<h1>{{ title }}</h1>
and my testing module for the component:
import {TestBed, ComponentFixture, ComponentFixtureAutoDetect, async} from "#angular/core/testing";
import { By} from "#angular/platform-browser";
import { CategoriesComponent } from "../../../../components/catalog/categories/CategoriesComponent";
import { DebugElement } from "#angular/core";
let comp: CategoriesComponent;
let fixture: ComponentFixture<CategoriesComponent>;
let de: DebugElement;
let el: HTMLElement;
describe('BannerComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CategoriesComponent ],
providers: [
{ provide: ComponentFixtureAutoDetect, useValue: true }
]
});
TestBed.compileComponents();
fixture = TestBed.createComponent(CategoriesComponent);
comp = fixture.componentInstance; // BannerComponent test instance
// query for the title <h1> by CSS element selector
de = fixture.debugElement.query(By.css('h1'));
el = de.nativeElement;
}));
it('should display original title', () => {
expect(el.textContent).toContain(comp.title);
});
});
I have tried to implement TestBed.compileComponents() into into the component but wherever I put it it doesn't seem to work.
Can anyone see why this error is occurring or point me in the directoin of a solution?
Thanks!
compileComponents resolves asynchronously (as it makes an XHR for the template), so it returns a promise. You should handle anything requiring the resolution of the promise, inside of the then callback of the promise
TestBed.compileComponents().then(() =>{
fixture = TestBed.createComponent(CategoriesComponent);
comp = fixture.componentInstance; // BannerComponent test instance
// query for the title <h1> by CSS element selector
de = fixture.debugElement.query(By.css('h1'));
el = de.nativeElement;
});
I want to use Mathml inside Ionic2, I have added mathjax cdn in the index.html, and added CUSTOM_ELEMENTS_SCHEMA in app.module.ts
<script type="text/javascript" async src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=MML_CHTML"></script>
in #NgModule i use
import { NgModule,CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HelloIonicPage } from '../pages/hello-ionic/hello-ionic';
import { ItemDetailsPage } from '../pages/item-details/item-details';
import { ListPage } from '../pages/list/list';
import {MathmlComponent} from '../components/mathml-component/mathml-component';
#NgModule({
declarations: [
MyApp,
HelloIonicPage,
ItemDetailsPage,
ListPage,
MathmlComponent
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HelloIonicPage,
ItemDetailsPage,
ListPage
],
providers: [],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}
My mathml-component.ts is
import {Component} from "#angular/core";
#Component({
selector:'mathml-component',
template:`
<math>
<mstyle displaystyle="true">
<mover>
<mrow>
<mi>f</mi>
</mrow>
<mo>→</mo>
</mover>
</mstyle>
</math>
`
})
export class MathmlComponent{
constructor(){
console.log('done')
}
}
But I am getting error
polyfills.js:3 Unhandled Promise rejection: Template parse errors:
':math:mi' is not a known element:
1. If ':math:mi' is an Angular component, then verify that it is part of this module.
2. If ':math:mi' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message. ("
<mover>
<mrow>
[ERROR ->]<mi>f</mi>
</mrow>
<mo>→</mo>
"): MathmlComponent#5:10
':math:mrow' is not a known element:
Plz help.
I found the solution. Instead of using MathMl I use Tex/Latex in MAthjax.
I'm writing unit tests for an ionic2 app but I get following error when the template contains some ionic elements
e.g.
<ion-icon > </ion-icon>
Failed: No provider for Config! (Icon -> Config)
Any idea?
I don't see how the previous solution works, because Config needs App, which needs Platform, which needs Keyboard which needs... maybe it is because you do not configure testing module asynchronously, which you should ;) simply try this:
import { IonicModule } from 'ionic-angular';
import { YourTestedComponent } from './pathto.component.ts'
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ IonicModule.forRoot(this) ], // this loads ionic deps
declarations: [ YourTestedComponent ],
});
}));
This should fix it
Best of luck
you're not allowed to use template in #app, try to use templateUrl: 'build/app.html' and create a app.html with your tags in it.
I run into the same problem. This worked for me:
import { async, ComponentFixture, TestBed } from "#angular/core/testing";
import { Config, IonicModule } from "ionic-angular";
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
],
imports: [
IonicModule,
],
providers: [
Config,
],
});
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
});