change the value of the currentUser variable:
it('should open the menu when the button menu is clicked', () => {
const fixture = TestBed.createComponent(HeaderComponent);
const component = fixture.componentInstance;
component.currentUser = true;
fixture.detectChanges();
const menuDebugElement = fixture.debugElement.query(By.css('.menu-button'));
expect(menuDebugElement).toBeTruthy();
});
I created an entire test and it works for me
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TestTComponent } from './test-t.component';
import { By } from '@angular/platform-browser';
fdescribe('TestTComponent', () => {
let component: TestTComponent;
let fixture: ComponentFixture<TestTComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TestTComponent]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TestTComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
component.currentUser = true;
fixture.detectChanges();
const menuDebugElement = fixture.debugElement.query(By.css('.menu-button'));
expect(menuDebugElement).toBeTruthy();
});
});
Answer from Chris on Stack Overflowchange the value of the currentUser variable:
it('should open the menu when the button menu is clicked', () => {
const fixture = TestBed.createComponent(HeaderComponent);
const component = fixture.componentInstance;
component.currentUser = true;
fixture.detectChanges();
const menuDebugElement = fixture.debugElement.query(By.css('.menu-button'));
expect(menuDebugElement).toBeTruthy();
});
I created an entire test and it works for me
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TestTComponent } from './test-t.component';
import { By } from '@angular/platform-browser';
fdescribe('TestTComponent', () => {
let component: TestTComponent;
let fixture: ComponentFixture<TestTComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TestTComponent]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TestTComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
component.currentUser = true;
fixture.detectChanges();
const menuDebugElement = fixture.debugElement.query(By.css('.menu-button'));
expect(menuDebugElement).toBeTruthy();
});
});
The problem is fixture.detectChanges(); triggers change detaction cycle and when you read value from html component not finished to update itself.
You solve using "whenStable()" function
it('should open the menu when the button menu is clicked', () => {
const fixture = TestBed.createComponent(HeaderComponent);
component.currentUser = true;
fixture.detectChanges();
fixture.whenStable()
.then(() => {
const menuDebugElement = fixture.debugElement.query(By.css('.menu-button'));
expect(menuDebugElement).toBeTruthy();
});
});
angular - Angular2 unit test with @Input() - Stack Overflow
Angular Unit Test: Access template variable - Stack Overflow
Angular unit test input value - Stack Overflow
How do I update component variables in Angular unit tests?
this is from official documentation https://angular.io/docs/ts/latest/guide/testing.html#!#component-fixture. So you can create new input object expectedHero and pass it to the component comp.hero = expectedHero
Also make sure to call fixture.detectChanges(); last, otherwise property will not be bound to component.
Working Example
// async beforeEach
beforeEach( async(() => {
TestBed.configureTestingModule({
declarations: [ DashboardHeroComponent ],
})
.compileComponents(); // compile template and css
}));
// synchronous beforeEach
beforeEach(() => {
fixture = TestBed.createComponent(DashboardHeroComponent);
comp = fixture.componentInstance;
heroEl = fixture.debugElement.query(By.css('.hero')); // find hero element
// pretend that it was wired to something that supplied a hero
expectedHero = new Hero(42, 'Test Name');
comp.hero = expectedHero;
fixture.detectChanges(); // trigger initial data binding
});
If you use TestBed.configureTestingModule to compile your test component, here's another approach. It's basically the same as the accepted answer, but may be more similar to how angular-cli generates the specs. FWIW.
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DebugElement } from '@angular/core';
describe('ProductThumbnail', () => {
let component: ProductThumbnail;
let fixture: ComponentFixture<TestComponentWrapper>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
TestComponentWrapper,
ProductThumbnail
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
fixture = TestBed.createComponent(TestComponentWrapper);
component = fixture.debugElement.children[0].componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@Component({
selector: 'test-component-wrapper',
template: '<product-thumbnail [product]="product"></product-thumbnail>'
})
class TestComponentWrapper {
product = new Product()
}
You can use a spy to spy on the function and check what was passed as an argument. Let's assume your component is called MyComponent. In your unit test file you have (a bit shortened, but you should get the picture):
let myComponent: MyComponent = fixture.componentInstance;
// Set up a spy on your function
let spy = spyOn(myComponent, 'onOpenSharesModal').and.callThrough();
// After the function has been called somewhere in your component
expect(spy).toHaveBeenCalled();
// Check the arguments that were passed
expect(spy.calls.mostRecent().args[0]).toEqual(myComponent.modal);
This is assuming the modal template variable is accessible from your component.
First you will want to add the following line to your component so that you can reference the modal template variable:
@ViewChild('modal') myModal: TemplateRef<any>; // for testing
Now you can reference the component variable 'myModal' in your test:
it('should call onOpenSharesModal() when button clicked', () => {
const button = fixture.debugElement.query(By.css('button'));
const spy = spyOn(component, 'onOpenSharesModal');
button.triggerEventHandler('click', null);
fixture.detectChanges();
expect(spy).toHaveBeenCalled();
expect(spy).toHaveBeenCalledWith(component.myModal);
});
Here is a working StackBlitz to demonstrate.
Inputs don't have textContent, only a value. So expect(field.textContent).toBe('someValue'); is useless. That's probably what's failing. The second expectation should pass though. Here's a complete test.
@Component({
template: `<input type="text" [(ngModel)]="user.username"/>`
})
class TestComponent {
user = { username: 'peeskillet' };
}
describe('component: TestComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [FormsModule],
declarations: [ TestComponent ]
});
});
it('should be ok', async(() => {
let fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
fixture.whenStable().then(() => {
let input = fixture.debugElement.query(By.css('input'));
let el = input.nativeElement;
expect(el.value).toBe('peeskillet');
el.value = 'someValue';
el.dispatchEvent(new Event('input'));
expect(fixture.componentInstance.user.username).toBe('someValue');
});
}));
});
The important part is the first fixture.whenStable(). There is some asynchronous setup with the forms that occurs, so we need to wait for that to finish after we do fixture.detectChanges(). If you are using fakeAsync() instead of async(), then you would just call tick() after fixture.detectChanges().
Just add
fixture.detectChanges();
fixture.whenStable().then(() => {
// here your expectation
})