This question already has answers here:
angular2 testing: Can't bind to 'ngModel' since it isn't a known property of 'input'
(2 answers)
Closed 5 years ago.
Trying to test my Angular application, but when trying to create my component I get multiple errors.
Can't bind to 'ngModel' since it isn't a known property of 'input'.
The pipe 'sortOnLike' could not be found.
'app-edit-message-modal' is not a known element:
If 'app-edit-message-modal' is an Angular component, then verify that it is part of this module.
If 'app-edit-message-modal' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message.
Answers to similar errors haven't helped me much.
dashboard.spec.ts
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { Router } from "#angular/router";
import { MockAF } from "../../providers/mockAf";
import { AF } from "../../providers/af";
import { DashboardComponent } from './dashboard.component';
describe('DashboardComponent', () => {
let component: DashboardComponent;
let fixture: ComponentFixture<DashboardComponent>;
let routerStub;
beforeEach(async(() => {
routerStub = {
navigate: jasmine.createSpy('navigate')
};
TestBed.configureTestingModule({
declarations: [ DashboardComponent ],
providers: [
{ provide: AF, useClass: MockAF },
{ provide: Router, useValue: routerStub },
],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Snippets from HTMLfile:
dashboard.component.html
<figure class="highlight">
<input type="textarea" class="message-text" [(ngModel)]="newMessage"
(keyup.enter)="sendMessage()">
<a class="send-message" (click)="sendMessage()">SEND</a>
</figure>
<a *ngIf="isMe(message.email)" type='edit' class='edit-text' style="cursor:
pointer;" (click)="show(message.$key, message.message)">Edit</a>
<!-- Modal (popup) for editing messages belonging to you -->
<app-edit-message-modal>
// modal form
</app-edit-message-modal>
<div *ngFor="let message of afService.messages | async |
sortOnLike:'votes':false">
snippets from dashboard.component.ts
import { Component, OnInit, AfterViewChecked, ElementRef, ViewChild } from
'#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { AF } from '../../providers/af';
import { FirebaseListObservable, AngularFire } from 'angularfire2';
import { Bubble } from './bubble';
import { EditMessageModalComponent } from '../edit-message-modal/edit-
message-modal.component';
show(key: string, message: string): void {
this.modalMessage = message;
this.modalMessageKey = key;
this.modal.show();
}
hide(): void {
this.modalMessage = null;
this.modalMessageKey = null;
this.modal.hide();
}
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 { RouterModule, Routes } from '#angular/router';
import { AngularFireModule } from 'angularfire2';
import { AppComponent } from './app.component';
import { RegistrationPageComponent } from './registration-page/registration-
page.component';
import { LoginPageComponent } from './login-page/login-page.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { AF } from '../providers/af';
import { FrontscreenComponent } from './frontscreen/frontscreen.component';
import { StudentDashboardComponent } from './student-dashboard/student-
dashboard.component';
import { LecturerDashboardComponent } from './lecturer-dashboard/lecturer-
dashboard.component';
import { firebaseConfig } from './config';
import { EditCourseModalComponent } from './edit-course-modal/edit-course-
modal.component';
import { EditMessageModalComponent } from './edit-message-modal/edit-
message-modal.component';
import { SortOnLikePipe } from './sort-on-like.pipe'
#NgModule({
declarations: [
AppComponent,
RegistrationPageComponent,
LoginPageComponent,
DashboardComponent,
FrontscreenComponent,
StudentDashboardComponent,
LecturerDashboardComponent,
EditCourseModalComponent,
EditMessageModalComponent,
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
AngularFireModule.initializeApp(firebaseConfig),
RouterModule.forRoot(routes),
SortOnLikePipe
],
providers: [AF],
bootstrap: [AppComponent],
})
export class AppModule { }
in your test, inside beforeEach block. You need to add the following to TestBed.configureTestingModule
All used pipes, components and directives have to be declared. in your case: SortOnLikePipe and EditMessageModalComponent
all used modules have to be imported. in your case: FormsModule
all needed services have to be provided
Here are the ones you are missing:
I'd imagine you might be missing more..
TestBed.configureTestingModule({
declarations: [ DashboardComponent, SortOnLikePipe, EditMessageModalComponent ],
imports:[FormsModule]
providers: [
{ provide: AF, useClass: MockAF },
{ provide: Router, useValue: routerStub },
],
})
Related
Currently I am struggling with an error after try to use a few mat components like "mat-form-field" or "mat-date-range-input" etc..
I've already imported them in the app.module file as I always do with these kind of component, but I get many errors like this:
If 'mat-form-field' is an Angular component, then verify that it is part of this module
If 'mat-label' is an Angular component, then verify that it is part of this module.
I have to say that in the same project I am using mat-tab-group and mat-tab etc... and I have not any errors with them.
These is my code:
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AngularMaterialModule } from './angular-material.module/angular-material.module.module';
import { MatButtonToggleModule } from '#angular/material/button-toggle';
import { MatSlideToggleModule } from '#angular/material/slide-toggle';
import { MatCardModule } from '#angular/material/card';
import { MatFormFieldModule } from '#angular/material/form-field';
import { MatInputModule } from '#angular/material/';
import { MatIconModule } from '#angular/material/icon';
import { ClipboardModule } from '#angular/cdk/clipboard';
#NgModule({
declarations: [], // I've omitted this part because is not relevant to this issue
imports: [
BrowserModule,
AppRoutingModule,
AngularMaterialModule,
MatProgressSpinnerModule,
MatButtonToggleModule,
MatSlideToggleModule,
MatCardModule,
MatFormFieldModule,
MatInputModule,
MatIconModule,
ClipboardModule
],
providers: [{provide: LocationStrategy, useClass: PathLocationStrategy}],
bootstrap: [AppComponent]
})
export class AppModule { }
And my component : create.report.component.html
<mat-form-field appearance="fill">
<mat-label>Enter a date range</mat-label>
<mat-date-range-input [formGroup]="reportForm" [rangePicker]="picker">
<input matStartDate formControlName="from" placeholder="Start date">
<input matEndDate formControlName="to" placeholder="End date">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>
</mat-form-field>
create.report.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, Validators, FormGroup, FormArray, FormControl } from '#angular/forms';
import { Router } from '#angular/router';
#Component({
selector: 'app-report',
templateUrl: './create.report.component.html'
})
export class CreateReportComponent implements OnInit {
reportForm = new FormGroup({
from: new FormControl(),
to: new FormControl()
});
constructor(
private router: Router,
private fb: FormBuilder) {
this.buildForm();
}
ngOnInit(): void {
}
buildForm() {
// console.log('***buildForm this.hmService***', this.hmService);
this.reportForm = this.fb.group( {
from : [ '', [Validators.required, Validators.minLength(5)]],
to: [ '', [Validators.required, Validators.minLength(5)]],
published : [ '', [Validators.required, Validators.minLength(5)]]
});
}
}
Ok, finally I solved!
With this line I fix the issue I had with material components. Now I can use them in my create.report.component .
import { CreateReportComponent } from './pages/report/create/create.report.component';
Having problems runnign my unit test code, getting this error message when trying to run the test:
Uncaught Error: Error in package:454:50:17 caused by: Invalid argument '[object
Object]' for pipe 'AsyncPipe'
at ViewWrappedError.ZoneAwareError
dashboard.component.spec.ts
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { FormsModule } from '#angular/forms';
import { Router, ActivatedRoute } from "#angular/router";
import { MockAF } from "../../providers/mockAf";
import { AF } from "../../providers/af";
import { DashboardComponent } from './dashboard.component';
import { SortOnLikePipe } from '../sort-on-like.pipe'
import { EditMessageModalComponent } from '../edit-message-modal/edit-
message-modal.component';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/observable/of';
import { MockModal } from '../edit-course-modal/mockEdit-course-
modal.component';
describe('DashboardComponent', () => {
let component: DashboardComponent;
let fixture: ComponentFixture<DashboardComponent>;
let routerStub;
beforeEach(async(() => {
routerStub = {
navigate: jasmine.createSpy('navigate')
};
TestBed.configureTestingModule({
declarations: [
DashboardComponent,
SortOnLikePipe,
EditMessageModalComponent,
],
imports: [
FormsModule,
],
providers: [
{ provide: AF, useClass: MockAF },
{ provide: Router, useValue: routerStub },
{ provide: EditMessageModalComponent, useClass: MockModal },
{ provide: ActivatedRoute, useValue: { queryParams: Observable.from([{
course: "TDT4001" }]) }},
],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
This is where i use pipes in my code
dashboard.component.html
<div *ngFor="let message of afService.messages | async |
sortOnLike:'votes':false">
.....
</div>
dashboard.component.ts
import { Component, OnInit, AfterViewChecked, ElementRef, ViewChild } from
'#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { AF } from '../../providers/af';
import { FirebaseListObservable, AngularFire } from 'angularfire2';
import { Bubble } from './bubble';
import { EditMessageModalComponent } from '../edit-message-modal/edit-
message-modal.component';
#Component({
moduleId: module.id.toString(),
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit, AfterViewChecked {
constructor(public afService: AF, private router: Router, private route:
ActivatedRoute) {
}
ngOnInit(): void {
var sub = this.route
.queryParams
.subscribe(params => {
// Defaults to error if no query param provided.
this.afService.setCourse(params['course'] || "error");
});
}
I have no clue on how to fix this problem, the funny thing is that it all worked. But when i got home to continue testing i got this error. All help is appreciated :)
I have a small Angular v4.x using Angluar Material 2.x
It has a modal (using MdDialog) login component - and pretty much nothing else.
All my tests are failing with:
Failed: No provider for FocusTrapFactory! at injectionError
(http://localhost:9876/base/src/test.ts?31c6eb17e2414560f8e07e35e9c56bebb408ba58:2074:86)
[angular]
at noProviderError (http://localhost:9876/base/src/test.ts?31c6eb17e2414560f8e07e35e9c56bebb408ba58:2112:12)
[angular] ...
my login.component.spec.ts is
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { FormsModule } from '#angular/forms';
import { RouterTestingModule } from '#angular/router/testing';
import { BrowserDynamicTestingModule } from '#angular/platform-browser-dynamic/testing';
import { NoopAnimationsModule } from '#angular/platform-browser/animations';
import { MdDialog, MdDialogContainer, MdInputContainer, OVERLAY_PROVIDERS } from '#angular/material';
import { HttpModule } from '#angular/http';
import { AuthenticationService } from '../shared/servicesIndex';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
beforeEach(async(() => {
TestBed.overrideModule(BrowserDynamicTestingModule, {
set: {
entryComponents: [MdDialogContainer]
}
});
TestBed.configureTestingModule(
{
imports: [
FormsModule,
RouterTestingModule,
HttpModule,
NoopAnimationsModule
],
declarations: [
LoginComponent,
MdInputContainer,
MdDialogContainer
],
providers: [
MdDialog,
OVERLAY_PROVIDERS,
AuthenticationService
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Logic tells me to import FocusTrapFactory and add it to my list of providers - but I can't find it to import it!
I'm at a loss. My Google-fu is fu.
Just needed to add import { MaterialModule } from '#angular/material'; then add MaterialModule to the imports array in my app.component.spec.ts.
You should add the right packages for the material components. Unfortunately MaterialModule is marked depricated in the latest release.
The best way to replace this is to make your own Module that imports (and exports) only the modules that are actually used in your application.
I managed to fix this issue by creating this class:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { MdMenuModule, MdIconModule, MdRippleModule, MdToolbarModule, MdSidenavModule, MdButtonModule } from '#angular/material'
// Add animations
import { BrowserAnimationsModule } from '#angular/platform-browser/animations'
const MATERIAL_MODULES = [
MdMenuModule,
MdIconModule,
MdRippleModule,
MdToolbarModule,
MdSidenavModule,
MdButtonModule,
BrowserAnimationsModule
];
#NgModule({
imports: MATERIAL_MODULES,
exports: MATERIAL_MODULES
})
export class AngularMaterialModule { }
This module should be included in your own app.module
Good luck!
I have spent a while getting the hang of modules in Angular2 and really like them but I am a little uncertain as to best approach for testing both my modules and the components within. (I also realise that my app.component can and probably should be broken out more but for now it is helpful while learning the testing framework to be a little more complex)
For example this is my app.module:
import { createStore, compose, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import { AUTH_PROVIDERS } from 'angular2-jwt';
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { ComponentsModule } from './components';
import { MaterialModule} from './material';
import { RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { ViewsModule } from './+views';
import { rootReducer } from './dataStore';
import { CurrentUserModel } from './models/current-user'
const appStore = createStore(rootReducer, applyMiddleware(ReduxThunk));
const APP_DECLARATIONS = [
AppComponent
];
const APP_PROVIDERS = [
{ provide: 'AppStore', useValue: appStore },
CurrentUserModel
];
#NgModule({
imports:[
FormsModule,
BrowserModule,
RouterModule,// here as well as in our Views Module because of router-outlet
ViewsModule,
MaterialModule, // here as well as in our Views & componet Module because used in App componet
ComponentsModule
],
declarations: APP_DECLARATIONS,
bootstrap:[AppComponent],
providers: APP_PROVIDERS,
})
export class AppModule {
}
and this is what my app.component looks like:
import { Component, ViewChild, AfterViewInit } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app',
styleUrls:['app.component.scss'],
template: `
<md-toolbar>
<!-- <i class="material-icons demo-toolbar-icon">menu</i> -->
<span class="toolbar-brand">Franks</span>
<span *ngIf="searchActive" role="search" class="fill-remaining-space">
<span class="search-input-container flex flex-1">
<i class="material-icons search-link">search</i>
<input class="search-input" placeholder="Search" type="text" id="searchInput" #searchInput (keyup.esc)="exitSearch($event)"/>
</span>
</span>
<i *ngIf="searchActive" class="material-icons right selectable" (click)="exitSearch($event)">close</i>
<span *ngIf="!searchActive" class="fill-remaining-space">
</span>
<span *ngIf="!searchActive" role="navmenu">
<span class="hlink" routerLink="/" routerLinkActive="active">home</span>
<span class="hlink" routerLink="/profile" routerLinkActive="active">Profile</span>
<span class="hlink" routerLink="/login" routerLinkActive="active">Login</span>
<span class="hlink" routerLink="/signup" routerLinkActive="active">Sign Up</span>
<i class="material-icons search-link" (click)="activeSearch($event)">search</i>
</span>
</md-toolbar>
<div class="container">
<router-outlet></router-outlet>
</div>
`,
})
export class AppComponent {
#ViewChild('searchInput') searchInputRef;
ngAfterViewChecked() {
if(this.searchActive && this.searchInputRef){
console.log(this.searchInputRef);
this.searchInputRef.nativeElement.focus();
}
}
searchActive: boolean;
constructor(public router: Router) {
this.searchActive = false;
}
activeSearch(event):void {
this.searchActive = true;
}
exitSearch(event) : void {
this.searchActive = false;
}
}
So I know I can potentially mock out all the Components with for example the MaterialComponents (this is just a wrapper module for the material components) within my tests but this seems a little tedious. Is that my only options and if so does it make sense to make creating a mock of components when creating the components part of the process.
for informational purposes this is what my material module looks like and my views and components modules are similar:
import { NgModule } from '#angular/core';
// Material
import { MdCardModule } from '#angular2-material/card';
import { MdButtonModule } from '#angular2-material/button';
import { MdInputModule } from '#angular2-material/input';
import { MdToolbarModule } from '#angular2-material/toolbar';
import { MdListModule } from '#angular2-material/list';
import { MdIconModule, MdIconRegistry } from '#angular2-material/icon';
const MATERIAL_UI_MODULES = [
MdCardModule,
MdButtonModule,
MdInputModule,
MdToolbarModule,
MdIconModule,
MdListModule
]
const MATERIAL_UI_REGISTRIES = [
MdIconRegistry
]
#NgModule({
imports:[
...MATERIAL_UI_MODULES,
],
providers: MATERIAL_UI_REGISTRIES,
exports:[
...MATERIAL_UI_MODULES,
]
})
export class MaterialModule {
}
So I eventually figured out how to do this and this is my current solution:
/* tslint:disable:no-unused-variable */
import { TestBed, inject, async } from '#angular/core/testing';
import { RouterTestingModule } from '#angular/router/testing';
import { By } from '#angular/platform-browser';
import { Component,ViewChild, AfterViewChecked } from '#angular/core';
import { Router } from '#angular/router';
import { Location, CommonModule } from '#angular/common';
import { MaterialModule} from './material';
#Component({
template: '<div></div>'
})
class DummyComponent {
}
import { AppComponent } from './app.component';
describe('component: TestComponent', function () {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
CommonModule,
RouterTestingModule.withRoutes([
{ path: 'profile', component: DummyComponent },
{ path: 'login', component: DummyComponent },
{ path: 'signup', component: DummyComponent },
{ path: '', component: DummyComponent }
]),
MaterialModule
],
declarations: [ AppComponent, DummyComponent ]
});
});
it('should create the app', async(() => {
let fixture = TestBed.createComponent(AppComponent);
let app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it('should be navigate to correct url for each option in navmenu',
async(inject([Router, Location], (router: Router, location: Location) => {
let fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
fixture.debugElement.query(By.css('span.hlink[routerLink="/profile"]')).nativeElement.click();
fixture.whenStable().then(() => {
expect(location.path()).toEqual('/profile');
expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/profile"]')).classes['active']).toBeTruthy();
expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)
fixture.debugElement.query(By.css('span.hlink[routerLink="/login"]')).nativeElement.click();
return fixture.whenStable();
}).then(() => {
expect(location.path()).toEqual('/login');
expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/login"]')).classes['active']).toBeTruthy();
expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)
fixture.debugElement.query(By.css('span.hlink[routerLink="/signup"]')).nativeElement.click();
return fixture.whenStable();
}).then(() => {
expect(location.path()).toEqual('/signup');
expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/signup"]')).classes['active']).toBeTruthy();
expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)
fixture.debugElement.query(By.css('span.hlink[routerLink="/"]')).nativeElement.click();
return fixture.whenStable();
}).then(() => {
expect(location.path()).toEqual('/');
expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/"]')).classes['active']).toBeTruthy();
expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)
});
})));
});
I am starting a project using Angular 2.0.0 stable release created with angular-cli 1.0.0-beta.14 and angulartics 1.1.9.
I am trying to start some simple unit testing and am recording clicks on a button component
<div class="sidebar-toggle" (click)="toggleSideBar()" angulartics2On="click" angularticsCategory="{{ expanded ? 'expand': 'collapse' }}">
//divContent
</div>
However, when I run the test which is simple bootstrapping the component I get the error
Can't bind to 'angularticsCategory' since it isn't a known property of 'div'
The app works fine but the issue only comes up in testing. I can't find an example where someone is having the same error in testing. I know I am missing something like not properly exposing the angulartics2 lib in my karma.conf OR not injecting the Angulartics or a mocked dependency in my Testbed config.
Really lost and would like to know if anyone is having similar problems. Can provide more code snippets if needed but don't want to dump the whole file nobody's got time to read that!
In my case to get Angulatics2 unit tests to work I had to:
1) Import Angulartics2Module into the root app.module.ts
import { Angulartics2Module } from 'angulartics2';
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
#NgModule({
declarations: [
AppComponent,
HeaderComponent,
],
imports: [
BrowserModule,
Angulartics2Module.forRoot({ developerMode: !environment.production }),
AppRoutingModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
2) Enable tracking in app.component.ts
import { Angulartics2GoogleGlobalSiteTag } from 'angulartics2/gst';
import { Component } from '#angular/core';
import { RouterOutlet } from '#angular/router';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
constructor(
public angulartics2GoogleGlobalSiteTag: Angulartics2GoogleGlobalSiteTag,
) {
this.angulartics2GoogleGlobalSiteTag.startTracking();
}
}
3) Import Angulartics2Module.forRoot() and Angulartics2 provider in to app.component.spec.ts
import { HttpClientTestingModule } from '#angular/common/http/testing';
import { TestBed, async } from '#angular/core/testing';
import { RouterTestingModule } from '#angular/router/testing';
import { Angulartics2, Angulartics2Module } from 'angulartics2';
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
Angulartics2Module.forRoot(),
HttpClientTestingModule,
],
declarations: [
AppComponent,
HeaderComponent,
],
providers: [
Angulartics2,
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
});
and for any other component.spec.ts files that you have using the Angulatics2 directives.