Angular 9 FormModule Unit Testog - javascript

So I have an #Input form: FormGroup.
Unit Testing
describe('Component', () => {
let component: Component;
let fixture: ComponentFixture<Component>;
let apiService: ApiService;
let fb: FormBuilder = new FormBuilder();
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [Component, TranslatePipeMock],
imports: [ReactiveFormsModule, FormsModule],
providers: [
ChangeDetectorRef,
{ provide: FormBuilder, useValue: fb },
{
provide: ApiService,
useValue: apiServiceStub,
},
{
provide: TranslateService,
userValue: translateServiceStub,
},
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
apiLookupService = TestBed.inject(ApiLookupService);
fixture = TestBed.createComponent(InputWhtComponent);
fb = TestBed.inject(FormBuilder);
component = fixture.componentInstance;
const expectedForm = fb.group({
isWithholdingTaxEnabled: new FormControl(true),
});
component.form = expectedForm;
fixture.detectChanges();
});
But i am having this error right now,
No value accessor for form control with name: 'isWithholdingTaxEnabled'

Related

Can not implement unit test on components with ionic 5/ angular 11

I have created components and pages in my ionic 5 project.
The pages are working fine in unit tests.
But, the components are not being tested in the same way.
describe('component', () => {
let component: Component;
let fixture: ComponentFixture<Component>;
let modalSpy = jasmine.createSpyObj('Modal', ['present', 'onDidDismiss', 'catch', 'dismiss']);
modalSpy.onDidDismiss.and.returnValue(Promise.resolve(true));
let modalCtrlSpy = jasmine.createSpyObj('ModalController', ['create', 'dismiss']);
modalCtrlSpy.create.and.callFake(function () {
return modalSpy;
});
let popoverSpy = jasmine.createSpyObj('Popover', ['present', 'onDidDismiss', 'dismiss']);
popoverSpy.onDidDismiss.and.returnValue(Promise.resolve(true));
let popoverCtrlSpy = jasmine.createSpyObj('PopoverController', ['create', 'dismiss']);
popoverCtrlSpy.create.and.callFake(function () {
return popoverSpy;
});
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ Component ],
imports: [
IonicModule.forRoot(),
TranslateModule.forChild(),
ComponentsModule,
PipesModule,
TranslateModule.forRoot({
loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
})
],
providers: [
{ provide: ModalController, useValue: modalCtrlSpy },
{ provide: PopoverController, useValue: popoverCtrlSpy },
AppGlobalState,
IonContent,
HttpClient,
HttpHandler,
Http,
HttpClientTestingModule,
Api,
ConnectionBackend,
SQLiteService,
SQLite,
InAppBrowser,
RequestOptions
]
}).compileComponents();
}));
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(Component);
component = fixture.componentInstance;
fixture.detectChanges();
component.loading=false;
component.ngOnInit();
fixture.detectChanges();
}))
afterEach(async () => {
component.ngOnDestroy();
})
This does not show the component being loaded.
<ion-card *ngIf='loading'>
</ion-card>
<ion-card *ngIf='!loading'>
</ion-card>
public loading: boolean = true
ngOnInit() {
subscriber.subscribe(() => {
this.loading = false
})
}
another issue in the same code is when I added renderer2. It gives error can not read property style of undefined. for the function setStyle being used in code.
any help is appreciated.

Angular 9 testing component dependant on service with observable - Cannot read property 'subscribe' of undefined

I am deperately trying to test a component that is using a service. I use spy to mock it but every time I run tests it fails with exception:
Cannot read property 'subscribe' of undefined
My test looks like this:
describe('FilmOverviewComponent', () => {
let component: FilmOverviewComponent;
let fixture: ComponentFixture<FilmOverviewComponent>;
let filmsServiceSpy: jasmine.SpyObj<FilmsService>;
beforeEach(async(() => {
const spy = jasmine.createSpyObj('FilmsService',
['searchFilmByID']
);
TestBed.configureTestingModule({
declarations: [ FilmOverviewComponent ],
providers: [
{provide: AppTitleService, useValue: {getTitle: () => 'title'}},
{provide: ActivatedRoute, useValue: {params: of({id: 123})} },
{provide: FilmsService, useValue: spy}
]
})
.compileComponents();
filmsServiceSpy = TestBed.get(FilmsService);
}));
beforeEach(() => {
filmsServiceSpy.searchFilmByID.and.returnValue(Observable.create([{title: "", year: ""}]));
fixture = TestBed.createComponent(FilmOverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Methods used in the service:
searchFilmByID(movieID: string): Observable<Film> {
return this.http.get<Film>(this.getUrlWithID(movieID));
}
private getUrlWithID(movieID: string) {
return 'api/externalfilms/film/' + movieID;
}
I have no idea how to tackle this. I suspect that it would be resolved with some kind of mocking of subscribe method but I completely failed at that.
Thank you for your help in advance!
The error is from this.http.get<Film>....
There are 2 ways to solve it.
First way - mock http client service and call fake
describe('FilmOverviewComponent', () => {
let component: FilmOverviewComponent;
let fixture: ComponentFixture<FilmOverviewComponent>;
let filmsService: FilmsService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FilmOverviewComponent ],
imports: [ HttpClientTestingModule ],
providers: [
{provide: AppTitleService, useValue: {getTitle: () => 'title'}},
{provide: ActivatedRoute, useValue: {params: of({id: 123})} },
FilmsService
]
})
.compileComponents();
}));
beforeEach(() => {
filmsService = TestBed.inject(FilmsService);
/* Mock response */
const httpClient: HttpClient = TestBed.inject(HttpClient);
spyOn(httpClient, 'get').and.callFake(() => of({title: "", year: ""}));
fixture = TestBed.createComponent(FilmOverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Second way - call fake service method
const FilmsServiceStub = jasmine.createSpyObj('FilmsService', ['searchFilmByID']);
describe('FilmOverviewComponent', () => {
let component: FilmOverviewComponent;
let fixture: ComponentFixture<FilmOverviewComponent>;
let filmsService: FilmsService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FilmOverviewComponent ],
providers: [
{provide: AppTitleService, useValue: {getTitle: () => 'title'}},
{provide: ActivatedRoute, useValue: {params: of({id: 123})} },
{provide: FilmsService, useValue: FilmsServiceStub}
]
})
.compileComponents();
}));
beforeEach(() => {
filmsService = TestBed.inject(FilmsService);
/* Mock response */
spyOn(filmsService, 'searchFilmByID').and.callFake(() => of({title: "", year: ""}));
fixture = TestBed.createComponent(FilmOverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

How to test data-cy directive?

I don't know how to write unit-test for this directive. Can you help me?
import { Directive, ElementRef, Inject, Input, Renderer2 } from enter code here'#angular/core';
#Directive({
// tslint:disable-next-line:directive-selector
selector: '[data-cy]'
})
export class DataCyDirective {
#Input('data-cy') dataCy: string;
constructor(
private el: ElementRef,
private renderer: Renderer2,
#Inject('production') isProd: boolean
) {
if (isProd) {
renderer.removeAttribute(el.nativeElement, 'data-cy');
}
}
}
I'm found a solution
#Component({
template: `
<span id="expected" data-cy="elementCy"></span>
`
})
class DataCyDirectiveTestComponent implements OnInit {
constructor(#Inject('production') prod: boolean) {}
}
describe('DataCyDirective test version', () => {
let component: DataCyDirectiveTestComponent;
let fixture: ComponentFixture<DataCyDirectiveTestComponent>;
configureTestSuite();
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [DataCyDirectiveTestComponent, DataCyDirective],
providers: [{ provide: 'production', useValue: false }]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DataCyDirectiveTestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should NOT delete the data-cy attribute if production is not enabled', () => {
const el: ElementRef<HTMLElement> = fixture.debugElement.query(By.css('#expected'));
expect(el.nativeElement.getAttribute('data-cy')).not.toBeNull();
});
});

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' }
]

Unit test queryParams subscription (Angular5)

i'm having problems testing the logic inside ActivatedRoute queryParams subscription.
constructor(private router: Router, private route: ActivatedRoute, private auth: AuthService) {}
ngOnInit(): void {
this.route.queryParams.subscribe((params:any) => {
if(params['data']) {
this.handle(params['data']);
} else {
if (this.auth.isAuthenticated()) {
this.router.navigate(['/home']);
}
}
});
}
I would like to test:
If this.handle() is triggered when mocked params['data'] is supplied
If there is no params and this.auth.isAuthenticated() returns true that this.router.navigate is called
I have tried multiple things and i'm running out of ideas.
My test file:
describe('TestComponent', () => {
let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;
const mockService = {
navigate: jasmine.createSpy('navigate'),
isAuthenticated: jasmine.createSpy('isAuthenticated'),
queryParams: jasmine.createSpy('queryParams')
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [
{ provide: Router, useValue: mockService },
{ provide: ActivatedRoute, useValue: mockService },
{ provide: AuthService, useValue: mockService }
]
}).compileComponents();
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
mockService.navigate.calls.reset();
}));
it('should create the test component', () => {
expect(component).toBeTruthy();
});
it('should navigate away when authenticated', () => {
mockService.isAuthenticated.and.returnValue(true);
mockService.queryParams.and.callFake((data, params) => new Observable(o => o.next({ params: {} })));
component.ngOnInit();
expect(mockService.navigate).toHaveBeenCalledWith(['/home']);
});
});
But with that i get TypeError: this.route.queryParams.subscribe is not a function. I know that mockService.isAuthenticated.and.returnValue(true); is working correctly because before using subscription to params i had only this if statement inside ngOnInit().
I have tried to change the mockService to:
const mockService = {
navigate: jasmine.createSpy('navigate'),
isAuthenticated: jasmine.createSpy('isAuthenticated'),
queryParams: {
subscribe: jasmine.create('subscribe')
}
};
I also tried with:
const mockService = {
navigate: jasmine.createSpy('navigate'),
isAuthenticated: jasmine.createSpy('isAuthenticated'),
queryParams: {
subscribe: Observable.of({ params: {} })
}
};
But no success, for those last two i get Expected spy navigate to have been called with [ [ '/home' ] ] but it was never called.
So does someone know how to correctly test logic inside querParams subscription?
You can use rxjs observable in useValue to mock it.
const router = {
navigate: jasmine.createSpy('navigate')
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([]),
RouterTestingModule,
PlanPrimengModule
],
declarations: [YourComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
provideMockStore(),
{
provide: ActivatedRoute,
useValue: {
queryParams: of({
param1: "value1",
param1: "value2"
})
}
},
{ provide: Router, useValue: router }
]
}).compileComponents(); }));
I can't say if it is too late to answer this or not, but maybe it will help new googlers...
I manage to solve that this way:
class ActivatedRouteMock {
queryParams = new Observable(observer => {
const urlParams = {
param1: 'some',
param2: 'params'
}
observer.next(urlParams);
observer.complete();
});
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [
HttpClient,
HttpHandler,
ControlContainer,
{
provide: ActivatedRoute,
useClass: ActivatedRouteMock
}
]
}).compileComponents();
injector = getTestBed();
httpMock = injector.get(HttpTestingController);
}));
That allows you to assert the logic inside your .subscribe(() => {}) method..
Hope it hepls

Categories

Resources