Stubbing nested component with its own nested components in angular test - javascript

I have a component (Parent), which has a custom nested component (ChildOne) which has its own custom nested component (ChildTwo). I want to unit test Parent, so I have created stubs for the children. However, stubbing a component seems to cause it not to have any children, so ChildTwo is missing which is needed for my test. Is there a way I can stub a component, while keeping it's children?
HTML:
<app-child-one>
<p></p>
<div>
<app-child-two (click)="onClick($event)">
</app-child-two>
</div>
</app-child-one>
Typescript:
#Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss']
})
export class ParentComponent {
onClick(event: Event) {
console.log(event);
}
}
Spec:
#Component({ selector: 'app-child-one', template: '' })
export class ChildOneStubComponent {
}
#Component({ selector: 'app-child-two', template: '' })
export class ChildTwoStubComponent {
}
describe('ParentComponent', () => {
let component: ParentComponent;
let fixture: ComponentFixture<ParentComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [
ParentComponent, ChildOneStubComponent, ChildTwoStubComponent
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ParentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeDefined();
});
it('calls onClick when child two is clicked', () => {
const childTwo = fixture.debugElement.query(By.css('app-child-two'));
childTwo.triggerEventHandler('click', null); // <-- this fails, child two is null
expect(...);
});

I think I've solved this myself, I just had to add <ng-content></ng-content> to the stub template and now it seems to work.
#Component({ selector: 'app-child-one', template: '<ng-content></ng-content>' })
export class ChildOneStubComponent {
}

Related

Angular unit test case- Cannot read properties of undefined (reading 'forEachNode')

I am trying to write unit test cases for Grid, for this I need to loop through gridapi data but it is giving me Cannot read undefined forEachNode error.
myComponent.component.ts.
import { Component, OnInit, } from '#angular/core';
import { GridOptions, GridApi, } from "ag-grid-community";
#Component({
selector: 'my-component',
templateUrl: './mycomponent.component.html',
styleUrls: ['./mycomponent.component.scss']
})
export class MyComponent implements OnInit {
grid: GridOptions;
data;
constructor() {}
getData() {
this.grid.api.forEachNode((node) =>
this.data.push(node.data.id);
);
}
}
mycomponent.component.spec.ts:
import { ComponentFixture, TestBed, waitForAsync } from '#angular/core/testing';
import { Mycomponent} from './mycomponent.component';
describe('Mycomponent', () => {
let component: Mycomponent;
let fixture: ComponentFixture<Mycomponent>;
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [Mycomponent],
}).compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(Mycomponent);
component = fixture.componentInstance;
const gridObj = jasmine.createSpyObj('grid', [
'api',
]);
gridObj.grid.api.and.returnValue({
context: {}
data : { id:1,name: 'columName'}
});
component.grid = gridObj;
fixture.detectChanges();
});
it(`should call getData method.`, () => {
component.getData();
expect(component.data).toEqual('[1]');
});
});
When I try to run above test case,
TypeError: Cannot read properties of undefined (reading 'forEachNode').
Can any one tell me where I am doing wrong.

HTML code only shows {{title}} instead of variable name

I'm currently following this tuturial: https://www.youtube.com/watch?v=WlAq06Z_25Y&list=PL8p2I9GklV45JZerGMvw5JVxPSxCg8VPv&index=4
what i want
but html only shows
what i get:
i'm trying to learn angular but it's verry confusing if you try to follow a turturial but some things just dont match up
code:
app.module.ts code:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'blog';
}
app.component.html code:
<h1>Hello World !</h1>
<h2>{{title}}</h2>
app.component.spec.ts code:
import { TestBed } from '#angular/core/testing';
import { RouterTestingModule } from '#angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'blog'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('blog');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('blog app is running!');
});
});
You need to run your app with ng serve and then verify your output on localhost:4200.
In case you need to run it on any other port, use ng serve --port:portnumber
Try creating a public method to pass it between your components:
export class AppComponent {
public title = "blog";
}
<h2>{{ title }}</h2>
i used port 5200 but i should use port 4200 instead. now it works

How to provide injected values while unit testing a component in angular5+

I am writing tests for a component that is initialized dynamically as a modal (entryComponent). Inputs for this component are retrieved via injector.
I need a way to provide these inputs in my component creation step in beforeEach.
this.modalService.create({
component: sampleComponent, inputs: {
test: 'testMsg'
}
});
SampleComponent:
#Modal()
#Component({
selector: 'sample-component',
templateUrl: './sample.component.html',
styleUrls: ['./sample.component.scss']
})
export class SampleComponent implements OnInit {
test: string;
constructor(private injector: Injector) {
}
ngOnInit() {
this.test= this.injector.get('test');
}
}
Test for sampleComponent:
describe('sampleComponent', () => {
let component: SampleComponent;
let fixture: ComponentFixture<SampleComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SampleComponent],
imports: [
ModalModule,
BrowserAnimationsModule,
],
providers: [
ModalService,
]
})
.compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(SampleComponent);
component = fixture.componentInstance;
fixture.detectChanges();
component.ngOnInit();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
test fails with:
Error: StaticInjectorError(DynamicTestModule)[test]:
StaticInjectorError(Platform: core)[test]:
NullInjectorError: No provider for test!
How do provide value for 'test' in this case?
In providers, provide values for the injected values that component is expecting:
providers: [
{ provide: 'test', useValue: 'valueOfTest' }
]

Angular 5 jasmine tests, component not compiling

I'm trying to write a simple unit test, but cannot get my template to compile. The AppComponent has one variable called text which renders to an h1 tag. When testing the html, this always comes back as ''. Does anyone know what I'm missing here?
Test code
import {TestBed, async, ComponentFixture} from '#angular/core/testing';
import {AppComponent} from './app.component';
describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
let component: AppComponent;
const mainTitle = 'Angular Unit Testing';
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
});
}));
it(`should render ${mainTitle} to an H1 tag`, async(() => {
const compiled = fixture.debugElement.nativeElement;
console.log('here', compiled.querySelector('h1'));
expect(compiled.querySelector('h1').textContent).toEqual(mainTitle);
}));
});
Component code
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
text = 'Angular Unit Testing';
}
HTML
<h1>{{text}}</h1>
You must set "text" public property of component-only then it will be rendered inside h1 tag
it(`should render ${mainTitle} to an H1 tag`, async(() => {
const compiled = fixture.debugElement.nativeElement;
component.text = 'Angular Unit Testing';
fixture.detectChanges();
expect(compiled.querySelector('h1').textContent).toEqual(mainTitle);
}));

Testing jquery code inside angular component using jasmine

I'm trying to test pieces of jquery code that are set on ngOnInit() of my angular app.These code adds and removes certain classes based on conditions that are identified using jquery functions.
Below is my component:
import { Component, OnInit, AfterContentInit } from '#angular/core';
declare var $: any;
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
constructor() { }
ngOnInit() {
if ($('#js-drawer') !== undefined && $('#js-drawer').hasClass('pxh-drawer--narrow#lg')) {
$('#gf-header').removeClass('pxh-view-header--animate-narrow pxh-view-header--narrow#lg');
} else if ($('#js-drawer') !== undefined && $('#js-drawer').hasClass('pxh-drawer--wide#lg')) {
$('#gf-header').addClass('pxh-view-header--animate-narrow pxh-view-header--narrow#lg');
}
}
}
and below is the test case that I tried.
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
declare var $;
fdescribe('AppComponent Test', () => {
let component: any;
let fixture: ComponentFixture<AppComponent>;
beforeEach(async(() => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
TestBed.configureTestingModule({
declarations: [AppComponent],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
it('test onInit function', () => {
const case1 = $('#js-drawer');
const case2 = $('#js-drawer').hasClass('pxh-drawer--narrow#lg');
spyOn($('#gf-header'), 'removeClass');
component.ngOnInit();
if (case1 && case2) {
expect($('#gf-header')).toHaveBeenCalledWith('removeClass');
}
});
});
Do let me know if this is the right way to test..Thanks

Categories

Resources