I'm a noob at unit testing, I've been trying to create a mock unit test for a HTTP call to an end point.
My Service:
this.http.get('endPoint',options).subscribe((res: Response) => {
let result = res.json();
let obj = new ForgotPasswordResponse(res..........);
return obj;
})
My Unit Test
it('should get response from server', (done) => {
let responseObj:ForgotPasswordResponse = {
messageEN: 'dsadsada',
messageFR: 'dsada',
headerEN: 'dsada',
headerFR: 'dsada',
pageTarget: 'dsada',
args: 'dsa',
systemLogs: 'dsada',
msgCode: 'dsa',
type: 'dsa'
}
let signinid = '1234';
let lang = 'EN';
backend.connections.subscribe((connection: MockConnection) => {
let options = new ResponseOptions({ body: responseObj });
connection.mockRespond(new Response(options));
expect(connection.request.url).toEqual('./api/v1/forgot/1234/EN');
expect(connection.request.method).toEqual(RequestMethod.Get);
});
subject.initPwdResetFlow(signinid, lang).subscribe((response) => {
expect(response).toEqual(responseObj);
done();
});
});
My response object is of type ForgotPasswordResponse, with the appropriate props. However, when I run the test, I get a failure -- it only says Type Error thrown.
To mock your HTTP connection, you have to inject the XHRBackend as follows:
my-service.spec.ts
import { HttpModule, XHRBackend, Response, ResponseOptions } from '#angular/http';
import { MockBackend, MockConnection } from '#angular/http/testing';
import { MyService } from './my-service';
(...)
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpModule
],
providers: [
MyService,
{provide: XHRBackend, useClass: MockBackend}
]
});
});
it('should get a response', (done) => {
inject([XHRBackend, MyService], (mockBackend: MockBackend, service: MyService) => {
const body = {content: 'blabla'};
const status = 200;
mockBackend.connections.subscribe((connection: MockConnection) => {
connection.mockRespond(new Response(new ResponseOptions({body, status})));
});
service.get().subscribe(response => {
expect(response).not.toBeNull();
done();
});
})();
});
Related
do I need to write a test for the below code?
#Post()
update(#Body() updateUserDto: UpdateUserDto, #Request() req) {
return this.userService.update(req.user.user, updateUserDto);
}
I'm going to make some assumptions about injected properties of the controller class. For full setups, you can view my testing example repo here. This should be essentially what you're looking for though
describe('UserController (Unit)', () => {
let controller: UserController;
let service: MockedClass<UserService>;
beforeAll(async () => {
const modRef = await Test.createTestingModule({
controllers: [UserController],
providers: [
{
provide: UserService,
useValue: {
update: jest.fn().mockReturnValue({ hello: 'world' }),
},
}
],
}).compile();
controller = modRef.get(UserController);
service = modRef.get(UserService);
});
it('should call update and return the value', () => {
const bodyVal = objectThatMatchesUpdateUserDto;
const reqVal = {
user: {
user: valueThatMatchesReqUserUser
}
};
const res = controller.update(bodyVal, reqVal);
expect(res).toEqual({ hello: 'world' });
expect(service.update).toBeCalledWith(reqVal.user.user, bodyVal)
});
});
I have started learning how to test angular projects. So far basic unit testing is working fine for me but for the dependency testing especially when API services are injected into the component I am facing issue for providing HttpClient. I have tried different solutions but none is working for me.
Service
// Present in HttpClientService file
getDisposition() {
return this.http.get<{ message: string, data: { dispositionList: Disposition[] } }>(`${this.URL}/disposition/get`);
}
// Present in FileProcessService file
deleteMedia(media: string) {
return this.http.delete<{ message: string }>(`${this.URL}/certificate/delete?certificate=${media}`);
}
add-edit-activity.component.ts
import { HttpEventType } from '#angular/common/http';
import { Component, ElementRef, Inject, OnInit, ViewChild } from '#angular/core';
import { FormBuilder, Validators } from '#angular/forms';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '#angular/material/dialog';
import { DomSanitizer, SafeUrl } from '#angular/platform-browser';
import { AssignedPerson } from '#model/assigned-person.model';
import { Disposition } from '#model/disposition.model';
import { mimeTypes } from '#model/mime-type';
import { FileProcessService } from '#service/file-process.service';
import { HttpClientService } from '#service/http-client.service';
import { DeleteComponent } from '#shared/delete/delete.component';
import { CustomErrorStateMatcher } from '#validator/error-state-matcher';
import { ToastrService } from 'ngx-toastr';
#Component({
selector: 'app-add-edit-activity',
templateUrl: './add-edit-activity.component.html',
styleUrls: ['./add-edit-activity.component.css']
})
export class AddEditActivityComponent implements OnInit {
constructor(private fb: FormBuilder, private sanitizer: DomSanitizer, private dialogRef: MatDialogRef<AddEditActivityComponent>, #Inject(MAT_DIALOG_DATA) public data: any,
private _http: HttpClientService, private _fileService: FileProcessService, private toastr: ToastrService, private dialog: MatDialog,) { }
re = new RegExp(/^[a-zA-Z-]*/, 'g');
ISOstamp = { T: ' ', Z: '000' };
matcher = new CustomErrorStateMatcher();
dispositionList: Disposition[] = [];
assignedPersonList: AssignedPerson[] = [];
filterAssignedPersonList: AssignedPerson[] = [];
uploaded = false;
uploadProgress = false;
fileURL: SafeUrl;
activityForm = this.fb.group({
gaugeId: [this.data.gaugeId, Validators.maxLength(9)], createTimeStamp: [{ value: new Date().toISOString().replace(/[TZ]/g, m => this.ISOstamp[m]), disabled: true }],
user: [{ value: sessionStorage.getItem('username'), disabled: true }], disposition: ['', [Validators.required, Validators.maxLength(30)]],
assignedPersonName: ['', Validators.maxLength(30)], department: ['', Validators.maxLength(20)],
shift: ['', Validators.maxLength(1)], remark: ['', Validators.maxLength(50)],
calibrationDate: ['', Validators.maxLength(10)], attachment: ['', Validators.maxLength(255)]
});
#ViewChild('file') certificate: ElementRef;
ngOnInit(): void {
this.data.type.match(this.re)[0] === 'Update' && this.setFormValues();
this._http.getDisposition().subscribe(response => this.dispositionList = response.data.dispositionList);
this._http.getAssignedPerson().subscribe(response => this.assignedPersonList = this.filterAssignedPersonList = response.data.assignedToList);
}
get GaugeId() {
return this.activityForm.get('gaugeId');
}
get TimeStamp() {
return this.activityForm.get('createTimeStamp');
}
get Attachment() {
return this.activityForm.get('attachment');
}
get Disposition() {
return this.activityForm.get('disposition');
}
get DispositionValue() {
return this.dispositionList.map(e => e.dispositionType).indexOf(this.Disposition.value) < 0;
}
get AssignedTo() {
return this.activityForm.get('assignedPersonName');
}
get AssignedToValue() {
return this.assignedPersonList.map(e => `${e.firstName} ${e.lastName}`).indexOf(this.Disposition.value) < 0;
}
private async setFormValues() {
this.activityForm.patchValue({ ...this.data });
if (this.data.attachment) {
this.uploadProgress = true;
this.uploaded = true;
await this.fetchUploadedFile(this.data.attachment, mimeTypes[this.data.attachment.split('.')[1]]);
this.activityForm.markAsPristine();
}
}
searchAssignedPerson(event) {
if (event.target.value) {
this.filterAssignedPersonList = [];
for (let person of this.assignedPersonList) {
if (person.firstName.toLowerCase().startsWith(event.target.value.toLowerCase())) {
this.filterAssignedPersonList.push(person);
}
}
} else { this.filterAssignedPersonList = this.assignedPersonList }
}
upload(event) {
const file: File = event.target.files[0];
this.certificate.nativeElement.value = '';
if (file.size > (20 * 1000 * 1000)) { // Checking if File size is above 20MB
this.toastr.error('Size of ' + file.name + ' is above 20MB');
return;
}
const fd = new FormData();
fd.append('certificate', file, file.name);
this.processAttachment(fd);
}
private processAttachment(file: FormData) {
this._fileService.uploadMedia(file).subscribe(event => {
if (event.type === HttpEventType.UploadProgress) { this.uploadProgress = true }
if (event.type === HttpEventType.Response) {
let media = event.body.data.Certificate;
this.fetchUploadedFile(media.fileName, media.fileType);
this.toastr.info(event.body.message);
}
}, error => {
this.toastr.error(error.error.message);
this.uploadProgress = false;
});
}
private async fetchUploadedFile(file: string, mimeType: string) {
try {
let response = await this._fileService.getMedia(file).toPromise();
this.fileURL = this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(new Blob([response], { type: mimeType })));
this.uploaded = true;
this.uploadProgress = false;
this.activityForm.patchValue({ attachment: file });
this.Attachment.markAsDirty();
} catch (error) {
this.uploadProgress = false;
this._fileService.processError(error.error)
}
}
deleteFile() {
this.dialog.open(DeleteComponent, {
width: '350px', disableClose: true
}).afterClosed().subscribe(response => {
if (response) {
this._fileService.deleteMedia(this.Attachment.value).subscribe(response => {
this.toastr.info(response.message);
this.activityForm.patchValue({ attachment: '' });
this.Attachment.markAsDirty();
this.uploaded = false;
}, error => this.toastr.error(error.error.message));
}
});
}
async doAction() {
let message = '';
if (this.data.type.match(this.re)[0] === 'Add') {
message = await (await this._http.addActivityLog(this.activityForm.getRawValue()).toPromise()).message;
} else {
message = await (await this._http.updateActivityLog(this.GaugeId.value, this.TimeStamp.value, this.activityForm.getRawValue()).toPromise()).message;
}
this.dialogRef.close(message);
}
}
add-edit-activity.component.spec.ts
import { ComponentFixture, TestBed, tick } from '#angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '#angular/material/dialog';
import { FileProcessService } from '#service/file-process.service';
import { HttpClientService } from '#service/http-client.service';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { AddEditActivityComponent } from './add-edit-activity.component';
describe('AddEditActivityComponent', () => {
let component: AddEditActivityComponent;
let fixture: ComponentFixture<AddEditActivityComponent>;
let _http: HttpClientService, _file: FileProcessService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AddEditActivityComponent],
imports: [FormsModule, ReactiveFormsModule],
providers: [
{ provide: MatDialogRef, useValue: {} },
{ provide: MAT_DIALOG_DATA, useValue: { type: 'Add Activity Log', gaugeId: 'W-001' } },,
{ provider: HttpClientService, useValue: null },
{ provider: FileProcessService, useValue: null }
]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AddEditActivityComponent);
component = fixture.debugElement.componentInstance;
_http = fixture.debugElement.injector.get(HttpClientService);
_file = fixture.debugElement.injector.get(FileProcessService);
fixture.detectChanges();
});
// These 2 tests throwing error.
it('SHOULD mock http service', () => {
let spy = spyOn(_http, 'getDisposition').and.callFake(() => {
return of({
message: '',
data: { dispositionList: [] }
}).pipe(delay(100));
});
component.ngOnInit();
tick(100);
expect(component.dispositionList).toEqual([]);
});
it('SHOULD mock file service', () => {
let spy = spyOn(_file, 'deleteMedia').and.callFake((file: string) => {
return of({ message: '' }).pipe(delay(100));
});
component.deleteFile();
tick(100);
expect(component.uploaded).toBe(false);
});
});
The error that am getting for those 2 tests (I'm providing the error of 1 test case, the same is coming for the 2nd one also):
SHOULD mock http service
AddEditActivityComponent
Error: Invalid provider for the NgModule 'DynamicTestModule' - only instances of Provider and Type are allowed, got: [..., ..., ...,
..., ?undefined?, ..., ...]
at throwInvalidProviderError (node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:240:1)
at providerToFactory (node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:11550:1)
at providerToRecord (node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:11521:1)
at R3Injector.processProvider (node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:11424:1)
Error: : could not find an object to spy upon for getDisposition() Usage: spyOn(, ) Error: :
could not find an object to spy upon for getDisposition() Usage:
spyOn(, )
at
Anyone, please help what's the exact error happening with my test cases? Stuck here for almost 2 days.
You have to avoid using a 'null' value when providing services in the TestBed, that what is causing your problem.
The best way to mock Angular services is to create SpyObj instances and then use them like what is done Angular tests documentation.
Here is how would be your spec file if you were using SpyObj:
import { ComponentFixture, TestBed, tick } from '#angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '#angular/material/dialog';
import { FileProcessService } from '#service/file-process.service';
import { HttpClientService } from '#service/http-client.service';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { AddEditActivityComponent } from './add-edit-activity.component';
describe('AddEditActivityComponent', () => {
let component: AddEditActivityComponent;
let fixture: ComponentFixture<AddEditActivityComponent>;
let httpSpy: jasmine.SpyObj<HttpClientService>;
let fileSpy: jasmine.SpyObj<FileProcessService>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AddEditActivityComponent],
imports: [FormsModule, ReactiveFormsModule],
providers: [
{ provide: MatDialogRef, useValue: {} },
{ provide: MAT_DIALOG_DATA, useValue: { type: 'Add Activity Log', gaugeId: 'W-001' } },
{
provider: HttpClientService,
useValue: jasmine.createSpyObj('HttpClientService', ['getDisposition', 'getAssignedPerson', 'addActivityLog', 'updateActivityLog'])
},
{
provider: FileProcessService,
useValue: jasmine.createSpyObj('FileProcessService', ['uploadMedia', 'getMedia', 'deleteMedia', 'processError'])
}
]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AddEditActivityComponent);
component = fixture.debugElement.componentInstance;
httpSpy = fixture.debugElement.injector.get(HttpClientService) as jasmine.SpyObj<HttpClientService>;
fileSpy = fixture.debugElement.injector.get(FileProcessService) as jasmine.SpyObj<FileProcessService>;
fixture.detectChanges();
});
// These 2 tests throwing error.
it('SHOULD mock http service', () => {
httpSpy.getDisposition.and.callFake(() => {
return of({
message: '',
data: { dispositionList: [] }
}).pipe(delay(100));
});
component.ngOnInit();
tick(100);
expect(component.dispositionList).toEqual([]);
});
it('SHOULD mock file service', () => {
fileSpy.deleteMedia.and.callFake((file: string) => {
return of({ message: '' }).pipe(delay(100));
});
component.deleteFile();
tick(100);
expect(component.uploaded).toBe(false);
});
});
I am trying to develop an application using NestJs as the backend framework. Currently I am writing some integration tests for the controllers.
This is my first project using typescript, I usually use Java/Spring but I wanted to learn and give nestJs a try.
I use different guards to access rest endpoints. In this case I have an AuthGuard and RolesGuard
To make the rest endpoint work I just add something like this in the TestingModuleBuilder:
.overrideGuard(AuthGuard())
.useValue({ canActivate: () => true })
The point is, is it possible to define or override this guards for each test to check that the request should fail if no guard or not allowed guard is defined?
My code for the test is the following one:
describe('AuthController integration tests', () => {
let userRepository: Repository<User>
let roleRepository: Repository<Role>
let app: INestApplication
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [
AuthModule,
TypeOrmModule.forRoot(typeOrmConfigTest),
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: jwtConfig.secret,
signOptions: {
expiresIn: jwtConfig.expiresIn
}
})
]
})
.overrideGuard(AuthGuard())
.useValue({ canActivate: () => true })
.overrideGuard(RolesGuard)
.useValue({ canActivate: () => true })
.compile()
app = module.createNestApplication()
await app.init()
userRepository = module.get('UserRepository')
roleRepository = module.get('RoleRepository')
const initializeDb = async () => {
const roles = roleRepository.create([
{ name: RoleName.ADMIN },
{ name: RoleName.TEACHER },
{ name: RoleName.STUDENT }
])
await roleRepository.save(roles)
}
await initializeDb()
})
afterAll(async () => {
await roleRepository.query(`DELETE FROM roles;`)
await app.close()
})
afterEach(async () => {
await userRepository.query(`DELETE FROM users;`)
})
describe('users/roles (GET)', () => {
it('should retrieve all available roles', async () => {
const { body } = await request(app.getHttpServer())
.get('/users/roles')
.set('accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
expect(body).toEqual(
expect.arrayContaining([
{
id: expect.any(String),
name: RoleName.STUDENT
},
{
id: expect.any(String),
name: RoleName.TEACHER
},
{
id: expect.any(String),
name: RoleName.ADMIN
}
])
)
})
})
It's not immediately possibly with the current implementation, but if you save the guard mock as a jest mock it should be possible. Something like this
describe('Controller Integration Testing', () => {
let app: INestApplication;
const canActivate = jest.fn(() => true);
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
})
.overrideGuard(TestGuard)
.useValue({ canActivate })
.compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
it('/ (GET) Fail guard', () => {
canActivate.mockReturnValueOnce(false);
return request(app.getHttpServer())
.get('/')
.expect(403);
});
});
I would like to be able to test my Nest service against an actual database. I understand that most unit tests should use a mock object, but it also, at times, makes sense to test against the database itself.
I have searched through SO and the GH issues for Nest, and am starting to reach the transitive closure of all answers. :-)
I am trying to work from https://github.com/nestjs/nest/issues/363#issuecomment-360105413. Following is my Unit test, which uses a custom provider to pass the repository to my service class.
describe("DepartmentService", () => {
const token = getRepositoryToken(Department);
let service: DepartmentService;
let repo: Repository<Department>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
DepartmentService,
{
provide: token,
useClass: Repository
}
]
}).compile();
service = module.get<DepartmentService>(DepartmentService);
repo = module.get(token);
});
Everything compiles properly, TypeScript seems happy. However, when I try to execute create or save on my Repository instance, the underlying Repository appears to be undefined. Here's the stack backtrace:
TypeError: Cannot read property 'create' of undefined
at Repository.Object.<anonymous>.Repository.create (repository/Repository.ts:99:29)
at DepartmentService.<anonymous> (relational/department/department.service.ts:46:53)
at relational/department/department.service.ts:19:71
at Object.<anonymous>.__awaiter (relational/department/department.service.ts:15:12)
at DepartmentService.addDepartment (relational/department/department.service.ts:56:16)
at Object.<anonymous> (relational/department/test/department.service.spec.ts:46:35)
at relational/department/test/department.service.spec.ts:7:71
It appears that the EntityManager instance with the TypeORM Repository class is not being initialized; it is the undefined reference that this backtrace is complaining about.
How do I get the Repository and EntityManager to initialize properly?
thanks,
tom.
To initialize typeorm properly, you should just be able to import the TypeOrmModule in your test:
Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
// ...
}),
TypeOrmModule.forFeature([Department])
]
I prefer not using #nestjs/testing for the sake of simplicity.
First of all, create a reusable helper:
/* src/utils/testing-helpers/createMemDB.js */
import { createConnection, EntitySchema } from 'typeorm'
type Entity = Function | string | EntitySchema<any>
export async function createMemDB(entities: Entity[]) {
return createConnection({
// name, // let TypeORM manage the connections
type: 'sqlite',
database: ':memory:',
entities,
dropSchema: true,
synchronize: true,
logging: false
})
}
Then, write test:
/* src/user/user.service.spec.ts */
import { Connection, Repository } from 'typeorm'
import { createMemDB } from '../utils/testing-helpers/createMemDB'
import UserService from './user.service'
import User from './user.entity'
describe('User Service', () => {
let db: Connection
let userService: UserService
let userRepository: Repository<User>
beforeAll(async () => {
db = await createMemDB([User])
userRepository = await db.getRepository(User)
userService = new UserService(userRepository) // <--- manually inject
})
afterAll(() => db.close())
it('should create a new user', async () => {
const username = 'HelloWorld'
const password = 'password'
const newUser = await userService.createUser({ username, password })
expect(newUser.id).toBeDefined()
const newUserInDB = await userRepository.findOne(newUser.id)
expect(newUserInDB.username).toBe(username)
})
})
Refer to https://github.com/typeorm/typeorm/issues/1267#issuecomment-483775861
Here's an update to the test that employs Kim Kern's suggestion.
describe("DepartmentService", () => {
let service: DepartmentService;
let repo: Repository<Department>;
let module: TestingModule;
beforeAll(async () => {
module = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot(),
TypeOrmModule.forFeature([Department])
],
providers: [DepartmentService]
}).compile();
service = module.get<DepartmentService>(DepartmentService);
repo = module.get<Repository<Department>>(getRepositoryToken(Department));
});
afterAll(async () => {
module.close();
});
it("should be defined", () => {
expect(service).toBeDefined();
});
// ...
}
I created a test orm configuration
// ../test/db.ts
import { TypeOrmModuleOptions } from '#nestjs/typeorm';
import { EntitySchema } from 'typeorm';
type Entity = Function | string | EntitySchema<any>;
export const createTestConfiguration = (
entities: Entity[],
): TypeOrmModuleOptions => ({
type: 'sqlite',
database: ':memory:',
entities,
dropSchema: true,
synchronize: true,
logging: false,
});
which I then utilize when setting up the tests
// books.service.test.ts
import { Test, TestingModule } from '#nestjs/testing';
import { HttpModule, HttpService } from '#nestjs/common';
import { TypeOrmModule, getRepositoryToken } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { BooksService } from './books.service';
import { Book } from './book.entity';
import { createTestConfiguration } from '../../test/db';
describe('BooksService', () => {
let module: TestingModule;
let service: BooksService;
let httpService: HttpService;
let repository: Repository<Book>;
beforeAll(async () => {
module = await Test.createTestingModule({
imports: [
HttpModule,
TypeOrmModule.forRoot(createTestConfiguration([Book])),
TypeOrmModule.forFeature([Book]),
],
providers: [BooksService],
}).compile();
httpService = module.get<HttpService>(HttpService);
service = module.get<BooksService>(BooksService);
repository = module.get<Repository<Book>>(getRepositoryToken(Book));
});
afterAll(() => {
module.close();
});
it('should be defined', () => {
expect(service).toBeDefined();
});
This allows to query the repository after the tests and ensure that the correct data was inserted.
I usually import AppModule for database connection, and finally after tests are executed I close the connection:
let service: SampleService;
let connection: Connection;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [AppModule, TypeOrmModule.forFeature([SampleEntity])],
providers: [SampleService],
}).compile();
service = module.get<SampleService>(SampleService);
connection = await module.get(getConnectionToken());
});
afterEach(async () => {
await connection.close();
});
I used existing AppModule for testing:
import { INestApplication } from '#nestjs/common';
import { NestFactory } from '#nestjs/core';
import { AppModule } from '../../../app.module';
import { AuthService } from '../auth.service';
describe('AuthService', () => {
let app: INestApplication;
let service: AuthService;
beforeAll(async () => {
app = await NestFactory.create(AppModule);
service = app.get(AuthService);
});
afterAll(async () => {
await app.close();
});
it('AuthService should be defined', () => {
expect(service).toBeDefined();
});
describe('login', () => {
it('should login user', async () => {
const user = await service.login({ email: 'xxxzei#mail.ru', password: '12345678' });
expect(user.id).toBeDefined();
});
});
});
Also to add env variables in your configuration file or AppModule:
import { config as testConfig } from 'dotenv';
if (process.env.NODE_ENV === 'test') {
testConfig({ path: resolve('./.env') });
}
Technologies Used: Karma/Jasmine, Angular2
service.ts
Injectable()
export class Service {
constructor(private http: Http) { }
getGoogle(): Observable<any>{
console.log("Inside service");
return this.http.get('https://jsonplaceholder.typicode.com/posts/1');
}}
Please ignore the Typos and all the imports are made correctly.API is getting called correctly in the UI.
service.spec.ts
describe('Provider:Service', () => {
const HERO_ONE = 'HeroNrOne';
const HERO_TWO = 'WillBeAlwaysTheSecond';
let lastConnection;
let service;
beforeEach(() => {
let injector = ReflectiveInjector.resolveAndCreate([
{ provide: ConnectionBackend, useClass: MockBackend },
{ provide: RequestOptions, useClass: BaseRequestOptions },
Http,
Service
]);
service = injector.get(Service);
let backend = injector.get(ConnectionBackend) as MockBackend;
backend.connections.subscribe((connection: any) => lastConnection = connection);
});
it('getGoogle() should return the data in json format', fakeAsync(() => {
console.log('1');
let result:String[];
service.getGoogle().toPromise().then((heroes:String[]) => result = heroes);
lastConnection.mockRespond(new Response(new ResponseOptions({
body:JSON.stringify({data: [HERO_ONE, HERO_TWO]}),
})));
tick();
console.log(result[0]);
console.log('3');
expect(result.length).toEqual(2, 'should contain given amount of
heroes'); //this spec is failing because results does is not getting the response.
}));
The result:String[] is not getting the response that is provided.