Reputation: 2937
I have Angular 9 project with Asp.Net core which uses SignalR. Everything is working perfectly fine, but I'm trying to figure out how to do proper unit testing on the component that its using signalr service inside Angular.
library used on frontend: "@aspnet/signalr": "^1.1.4"
This happens only on unit testing. The error that I'm getting is
Error: Failed to complete negotiation with the server: Error'
Chrome 91.0.4472 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.304 secs / 0.274 secs)
Error: Failed to start the connection: Error'
Chrome 91.0.4472 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.304 secs / 0.274 secs)
ERROR: 'Error'
Chrome 91.0.4472 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.304 secs / 0.274 secs)
ERROR: 'Error'
Chrome 91.0.4472 (Windows 10.0.0): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
Chrome 91.0.4472 (Windows 10.0.0): Executed 1 of 1 SUCCESS (0.3 secs / 0.271 secs)
My signalr.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { HubConnection } from '@aspnet/signalr';
import * as signalR from '@aspnet/signalr';
import { Observable } from 'rxjs';
import { SignalRConnectionInfo } from './signalr-connection-info.model';
import { Subject } from 'rxjs';
import { ApiService } from '../../api.service';
@Injectable()
export class SignalRService {
private hubConnection: HubConnection;
private apiHubConnection: HubConnection;
modelChange: Subject<any> = new Subject();
change: Subject<any> = new Subject();
constructor(private http: HttpClient, private apiService: ApiService, private authService: AuthenticationService) {}
private getConnectionInfo(): Observable<SignalRConnectionInfo> {
return this.http.get<SignalRConnectionInfo>(this.apiService.functionUrl + 'negotiate');
}
init() {
this.initApiHub();
this.getConnectionInfo().subscribe(info => {
const options = {
accessTokenFactory: () => info.accessToken
};
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(info.url, options)
.configureLogging(signalR.LogLevel.Information)
.build();
this.hubConnection.start().catch(err => console.error(err.toString())); // this is the error where it happens.
this.hubConnection.on('NotifyModelRunStatus', (data: any) => {
this.modelChange.next(data);
});
this.hubConnection.on('NotifyMoveOrderStatus', (data: any) => {
this.modelChange.next(data);
this.change.next(data);
});
});
}
initApi() {
const options = {
accessTokenFactory: () => this.authService.getAccessToken()
};
this.apiHubConnection = new signalR.HubConnectionBuilder()
.withUrl(this.apiService.apiBaseUrl, options)
.configureLogging(signalR.LogLevel.Error)
.build();
this.apiHubConnection.start()
.catch(err => console.error(err ? err.toString() : err));
// Add different SignalR methods from API signalR below
this.apiHubConnection.on('Some change', (data: any) => {
this.change.next(data);
});
this.apiHubConnection.on('Some change', (data: any) => {
this.change.next(data);
});
}
}
The component unit test where error is shown:
describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let signalRService: SignalRService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
CommonModule,
HttpClientTestingModule,
HttpClientModule,
ReactiveFormsModule,
FormsModule,
BrowserAnimationsModule,
],
declarations: [MyComponent],
providers: [
SignalRService,
ApiService,
HttpClient,
],
}).compileComponents();
apiService = TestBed.inject(ApiService);
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
},
};
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
I guess the issue is that I'm not mocking the signalr service in test component.
Upvotes: 1
Views: 1113
Reputation: 183
The concept of unit testing means you are only testing your component in its test, not other services. Hence you only need to assert the methods in the service has been invoked.
In your case, the "providers" in your test configuration should be a mock object instead of a real service.
describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let signalRServiceSpy: jasmine.SpyObj<SignalRService>; // changed
beforeEach(() => { // changed
signalRServiceSpy = jasmine.createSpyObj('SignalRService', ['yourMethodInService']); // added
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
CommonModule,
HttpClientTestingModule,
HttpClientModule,
ReactiveFormsModule,
FormsModule,
BrowserAnimationsModule,
],
declarations: [MyComponent],
providers: [
{ provide: SignalRService, useValue: signalRServiceSpy }, // changed
ApiService, // this should also use a spy object
HttpClient, // you might not need this
],
}).compileComponents();
apiService = TestBed.inject(ApiService);
});
beforeEach(() => {
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
});
Upvotes: 0