Return of api rest with node - node.js

Im trying to generate rest-api for Odoo - ERP whith Nestjs and odoo-xmlrpc. I can connect to odoo but i cant respose the values than odoo response to my service.
This is the odoo service that response a value or an error:
import { Injectable, OnModuleInit } from '#nestjs/common';
#Injectable()
export class OdooService {
private Odoo = require('odoo-xmlrpc');
public odoo;
constructor () {
this.odoo = new this.Odoo({
url: 'https:/www.xxxxxxxxx.xxx',
db: 'xxxx',
username: 'username',
password: 'password'
});
}
execute(model: string, funtion: string , params: any[], callback) {
const odoo = new this.Odoo({
url: 'https:/www.xxxxxxxxx.xxx',
db: 'xxxx',
username: 'username',
password: 'password'
});
odoo.connect(async function (error: any): Promise<any> {
if (error) {
console.log(error);
return [{}];
}
odoo.execute_kw(model, funtion, params, function (error: any, values: []) {
if (error) {
console.log('error :>> ', error);
return [{}];
}
callback(values);
})
})
}
}
this is the service that use the odooServive
import { Injectable } from '#nestjs/common';
import { OdooService } from '../odoo/odoo.service';
import { CreateCountryDto } from './dto/create-country.dto';
import { UpdateCountryDto } from './dto/update-country.dto';
#Injectable()
export class CountriesService {
constructor(
private odooService: OdooService
) {}
async findAll() {
return await this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }], async function (response: []) {
// console.log(response);
return await response;
});
}
}
odoo documentation: https://www.odoo.com/documentation/14.0/webservices/odoo.html
library documentation: https://www.npmjs.com/package/odoo-xmlrpc

Elaborating #charlietfl's comment into an answer, you can use one of these codes, either using callback, or using async await
No Promise, no callback
findAll() {
return this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }]);
}
Using callback, no need for Promise
findAll() {
this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }], function (response: []) {
return response;
});
}
Using Promise
async findAll() {
const response = await this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }]);
return response;
}

Related

How to mock a Promise in Jest inside a class (not imported from a library)

I am using the AWS SDK to send emails. I have the following implementation:
import { Injectable } from '#nestjs/common';
import * as AWS from 'aws-sdk';
import { SendEmailDTO } from 'src/Messages/application/DTO/Inputs';
#Injectable()
export class MailSenderSESSDKAdapter implements MailSenderPort {
constructor() {}
async send(params: SendEmailDTO): Promise<void> {
const sendPromise = new AWS.SES(config).sendEmail(params).promise();
sendPromise
.then(function (data) {
console.log('### MailSenderSESSDKAdapter sendPromise data', data);
})
.catch(function (err) {
console.error('### err', err);
});
}
}
This line:
const sendPromise = new AWS.SES(config).sendEmail(params).promise();
returns a promise and when resolved, if successful, you get back the MessageId of the sent email.
I am trying to test it, I tried following approaches:
import { MailSenderSESSDKAdapter } from '../mailSenderSESSDK.adapter';
jest.mock('../mailSenderSESSDK.adapter', () => {
return jest.fn().mockImplementation(() => {
return { sendPromise: jest.fn() };
});
});
describe('mailSenderSESSDK adapter', () => {
let adapter: MailSenderSESSDKAdapter;
let sendPromise: any;
const mockDataResponse = {
ResponseMetadata: {
RequestId: 'ABC123',
},
MessageId: 'abc-123',
};
beforeEach(async () => {
adapter = new MailSenderSESSDKAdapter();
sendPromise = jest.fn().mockResolvedValue(Promise);
});
it.only('sends an email via SES', async () => {
const sendEmailDTO = {
subject: 'foo subject',
body: 'foo body',
from: 'from#mail.com',
to: 'to#mail.com',
};
await adapter.send(sendEmailDTO);
await expect(sendPromise).resolves.toBe(mockDataResponse);
});
});
But I don't know how to mock a method within a class method. I know how to mock the send method, but not the sendPromise promise inside the send method.
Only idea that I have would be to create a method that wraps the creation of the promise, and then mock this method, but seems overkill.
Anyone knows how to do it or best practices?

Graphql Mysql - Get rows from a table in JSON Format

I'm working on Backend with TypeGraphQL and NodePostGres.
User will pass database id and table name. I need to send data in JSON Format.
I have tried below code but it doesn't return anything nor does it throw any error.
Service:
import { Service } from 'typedi'
import { Client } from 'pg'
import { databases } from './db'
import { Payload } from './models'
#Service()
export class PayloadService {
fetchPayload(id: number, tableName: string): Payload {
const databaseCredentials = databases.find((d) => d.id && +d.id === id)
if (!databaseCredentials) throw new Error('Invalid ID!')
const client = new Client({
host: databaseCredentials.host,
port: +(databaseCredentials.port || 5432),
user: databaseCredentials.username,
password: databaseCredentials.password,
database: databaseCredentials.database,
ssl: {
rejectUnauthorized: false,
},
})
console.log('before client')
client.query("select * from pg_tables where schemaname='public'", (err, res) => {
if (err) {
console.log(err.stack)
} else {
console.log(res.rows[0])
}
console.log(`callback`)
})
console.log('after client')
return {
id,
data: [],
}
}
}
Resolver:
import { Arg, Query, Resolver } from 'type-graphql'
import { Inject } from 'typedi'
import { Payload } from './models'
import { PayloadService } from './services'
#Resolver(Payload)
export class PayloadResolver {
#Inject()
private PayloadService: PayloadService
#Query((returns) => Payload)
payload(#Arg('databaseId') databaseId: number, #Arg('tableName') tableName: string) {
return this.PayloadService.fetchPayload(databaseId, tableName)
}
}

Nodejs Typescript Jest Unit Test Coverage shows some code to covered

This is my nodejs typescript class and written jest unit test for isHealthy() public method.
Test coverage shows that this.pingCheck() then block, catch and last return statement are not covered.
Please advise.
Can we do unit test for pingCheck private method ?
This my class
import { HttpService, Injectable } from '#nestjs/common';
import { DependencyUtlilizationService } from '../dependency-utlilization/dependency-utlilization.service';
import { ComponentType } from '../enums/component-type.enum';
import { HealthStatus } from '../enums/health-status.enum';
import { ComponentHealthCheckResult } from '../interfaces/component-health-check-result.interface';
import { ApiHealthCheckOptions } from './interfaces/api-health-check-options.interface';
#Injectable()
export class ApiHealthIndicator {
private healthIndicatorResponse: {
[key: string]: ComponentHealthCheckResult;
};
constructor(
private readonly httpService: HttpService,
private readonly dependencyUtilizationService: DependencyUtlilizationService,
) {
this.healthIndicatorResponse = {};
}
private async pingCheck(api: ApiHealthCheckOptions): Promise<boolean> {
let result = this.dependencyUtilizationService.isRecentlyUsed(api.key);
if (result) {
await this.httpService.request({ url: api.url }).subscribe(() => {
return true;
});
}
return false;
}
async isHealthy(
listOfAPIs: ApiHealthCheckOptions[],
): Promise<{ [key: string]: ComponentHealthCheckResult }> {
for (const api of listOfAPIs) {
const apiHealthStatus = {
status: HealthStatus.fail,
type: ComponentType.url,
componentId: api.key,
description: `Health Status of ${api.url} is: fail`,
time: Date.now(),
output: '',
links: {},
};
await this.pingCheck(api)
.then(response => {
apiHealthStatus.status = HealthStatus.pass;
apiHealthStatus.description = `Health Status of ${api.url} is: pass`;
this.healthIndicatorResponse[api.key] = apiHealthStatus;
})
.catch(rejected => {
this.healthIndicatorResponse[api.key] = apiHealthStatus;
});
}
return this.healthIndicatorResponse;
}
}
This is my unit test code.
I get the following error when I run npm run test
(node:7876) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'status' of undefined
(node:7876) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 6)
import { HttpService } from '#nestjs/common';
import { Test, TestingModule } from '#nestjs/testing';
import { DependencyUtlilizationService } from '../dependency-utlilization/dependency-utlilization.service';
import { ApiHealthIndicator } from './api-health-indicator';
import { ApiHealthCheckOptions } from './interfaces/api-health-check-options.interface';
import { HealthStatus } from '../enums/health-status.enum';
describe('ApiHealthIndicator', () => {
let apiHealthIndicator: ApiHealthIndicator;
let httpService: HttpService;
let dependencyUtlilizationService: DependencyUtlilizationService;
let dnsList: [{ key: 'domain_api'; url: 'http://localhost:3001' }];
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ApiHealthIndicator,
{
provide: HttpService,
useValue: new HttpService(),
},
{
provide: DependencyUtlilizationService,
useValue: new DependencyUtlilizationService(),
},
],
}).compile();
apiHealthIndicator = module.get<ApiHealthIndicator>(ApiHealthIndicator);
httpService = module.get<HttpService>(HttpService);
dependencyUtlilizationService = module.get<DependencyUtlilizationService>(
DependencyUtlilizationService,
);
});
it('should be defined', () => {
expect(apiHealthIndicator).toBeDefined();
});
it('isHealthy should return status as true when pingCheck return true', () => {
jest
.spyOn(dependencyUtlilizationService, 'isRecentlyUsed')
.mockReturnValue(true);
const result = apiHealthIndicator.isHealthy(dnsList);
result.then(response =>
expect(response['domain_api'].status).toBe(HealthStatus.pass),
);
});
it('isHealthy should return status as false when pingCheck return false', () => {
jest
.spyOn(dependencyUtlilizationService, 'isRecentlyUsed')
.mockReturnValue(false);
jest.spyOn(httpService, 'request').mockImplementation(config => {
throw new Error('could not call api');
});
const result = apiHealthIndicator.isHealthy(dnsList);
result
.then(response => {
expect(response['domain_api'].status).toBe(HealthStatus.fail);
})
.catch(reject => {
expect(reject['domain_api'].status).toBe(HealthStatus.fail);
});
});
});
Looks like you should define the status before initialize the unit test, try to grab some more logs using console.log and for the second test, added catch block to make sure you're grabing the failures

Unable to create Jest testing module on NestJs service. Geting Nest can't resolve dependencies of the UsersService (?, ConfigService)

it's my first time making questions on stackoverflow :).
So I'm developing a test / learning application to learn how to use NestJS and Vue.
I am was currently trying to implement several server-side unit tests (using Jest). When trying to create a testingmodule from my UsersService I get the error below on running "npm test users.service.spec"
Nest can't resolve dependencies of the UsersService (?,
ConfigService). Please make sure that the argument at index [0] is
available in the _RootTestModule context.
at Injector.lookupComponentInExports (../node_modules/#nestjs/core/injector/injector.js:183:19)
I am not sure if I am incorrectly instantiating the test model, or misconceived the injection of config.service, the code itself works, but may be implemented incorrectly.
Does anyone have any ideas how to solve this problem?
Git link: https://github.com/Lindul/FuelTracker_NestJs_MySql_Vue.git
users.service.spec.ts
import { Test } from '#nestjs/testing';
import { UsersService } from './users.service';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { ConfigService } from '../shared/config/config.service';
describe('User Service Tests', () => {
let loginTeste: UserLoginRegRequestDto = {
login: 'LoginJestTeste',
password: 'PassJestTeste',
}
const userMock: UserDto = {
id: 1,
login: 'hugombsantos',
password: 'wefewkfnwekfnwekjnf',
isActive: true,
needChangePass: false,
userType: 0,
};
const dataFindAllMock: UserDto[] = [{
id: 1,
login: 'hugombsantos',
password: 'wefewkfnwekfnwekjnf',
isActive: true,
needChangePass: false,
userType: 0,
}, {
id: 2,
login: 'user2',
password: 'sdgsdgdsgsdgsgsdg',
isActive: true,
needChangePass: false,
userType: 0,
}];
let service: UsersService;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
ConfigService,
UsersService,
],
}).compile();
service = module.get<UsersService>(UsersService);
});
it('UsersService está defenido', () => {
expect(service).toBeDefined();
});
});
user.service.ts
import { Injectable, Inject, HttpException, HttpStatus } from '#nestjs/common';
import { Users } from '../models/users.schema';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { UserLoginResponseDto } from './dto/user-login-response.dto';
import { sign } from 'jsonwebtoken';
import { ConfigService } from '../shared/config/config.service';
import { JwtPayload } from './auth/jwt-payload.model';
import { ErroMessageDto } from '../shared/config/dto/erro-message.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import bcrypt = require('bcrypt-nodejs');
const SALT_FACTOR = 8;
#Injectable()
export class UsersService {
constructor(
#Inject('UsersRepository') private usersRepository: typeof Users,
private readonly configService: ConfigService,
) { }
/* istanbul ignore next */
async findAll(): Promise<UserDto[]> {
const users = await this.usersRepository.findAll<Users>();
return users.map(user => {
return new UserDto(user);
});
}
/* istanbul ignore next */
async findUser(id: number): Promise<Users> {
const user = await this.usersRepository.findOne<Users>({
where: { id },
});
return user;
}
/* istanbul ignore next */
async findUserformLogin(login: string): Promise<UserDto> {
return await this.usersRepository.findOne<Users>({
where: { login },
});
}
/* istanbul ignore next */
async findUserforLogin(id: number, login: string): Promise<Users> {
return await this.usersRepository.findOne<Users>({
where: { id, login },
});
}
/* istanbul ignore next */
async creatUserOnDb(createUser: UserLoginRegRequestDto): Promise<Users> {
try {
const user = new Users();
user.login = createUser.login;
user.password = await this.hashPass(createUser.password);
return await user.save();
} catch (err) {
if (err.original.code === 'ER_DUP_ENTRY') {
throw new HttpException(
new ErroMessageDto(
HttpStatus.CONFLICT,
`Login '${err.errors[0].value}' already exists`),
HttpStatus.CONFLICT,
);
}
throw new HttpException(
new ErroMessageDto(
HttpStatus.INTERNAL_SERVER_ERROR,
err),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
/* istanbul ignore next */
async updateUserOnDb(user: Users): Promise<Users> {
try {
return await user.save();
} catch (err) {
if (err.original.code === 'ER_DUP_ENTRY') {
throw new HttpException(
new ErroMessageDto(
HttpStatus.CONFLICT,
`Login '${err.errors[0].value}' already exists`),
HttpStatus.CONFLICT,
);
}
throw new HttpException(
new ErroMessageDto(
HttpStatus.INTERNAL_SERVER_ERROR,
err),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
/* istanbul ignore next */
async delete(id: number): Promise<UserDto> {
const user = await this.findUser(+id);
await user.destroy();
return new UserDto(user);
}
async login(
userLoginRequestDto: UserLoginRegRequestDto,
): Promise<UserLoginResponseDto> {
const login = userLoginRequestDto.login;
const password = userLoginRequestDto.password;
const user = await this.findUserformLogin(login);
if (!user) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.UNAUTHORIZED,
'Invalid login or password.'),
HttpStatus.UNAUTHORIZED,
);
}
const isMatch = await this.comparePass(password, user.password);
if (!isMatch) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.UNAUTHORIZED,
'Invalid login or password.'),
HttpStatus.UNAUTHORIZED,
);
}
const token = await this.signToken(user);
return new UserLoginResponseDto(token);
}
async create(createUser: UserLoginRegRequestDto): Promise<UserLoginResponseDto> {
const userData = await this.creatUserOnDb(createUser);
// when registering then log user in automatically by returning a token
const token = await this.signToken(userData);
return new UserLoginResponseDto(token);
}
async updateUser(id: number | string, updateUserDto: UpdateUserDto): Promise<UserLoginResponseDto> {
const user = await this.findUser(+id);
if (!user) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.NOT_FOUND,
'User not found.'),
HttpStatus.NOT_FOUND,
);
}
user.login = updateUserDto.login || user.login;
user.userType = updateUserDto.userType || user.userType;
user.needChangePass = false;
const isMatch = await this.comparePass(updateUserDto.password, user.password);
if (updateUserDto.password && !isMatch) {
user.password = await this.hashPass(updateUserDto.password);
} else {
user.password = user.password;
}
const userData = await this.updateUserOnDb(user);
const token = await this.signToken(userData);
return new UserLoginResponseDto(token);
}
async signToken(user: UserDto): Promise<string> {
const payload: JwtPayload = {
id: user.id,
login: user.login,
};
const token = sign(payload, this.configService.jwtConfig.jwtPrivateKey,
{
expiresIn: this.configService.jwtConfig.valideTime,
});
return token;
}
async hashPass(passToHash: string): Promise<string> {
const saltValue = await bcrypt.genSaltSync(SALT_FACTOR);
return await bcrypt.hashSync(passToHash, saltValue);
}
async comparePass(passToCheck: string, correntPass: string) {
return await bcrypt.compareSync(passToCheck, correntPass);
}
}
users.modules.ts
import { Module } from '#nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import {userProviders} from './users.providers';
import { DatabaseModule } from '../database/database.module';
import { JwtStrategy } from './auth/jwt-strategy';
import { ConfigService } from '../shared/config/config.service';
#Module({
imports: [DatabaseModule, ConfigService],
controllers: [UsersController],
providers: [UsersService,
...userProviders, JwtStrategy],
exports: [UsersService],
})
export class UsersModule {}
config.service.ts
import { Injectable } from '#nestjs/common';
import { JwtConfig } from './interfaces/jwt-config.interface';
import { config } from '../../../config/config.JwT';
import { config as dbConfigData } from '../../../config/config.db';
import { SequelizeOrmConfig } from './interfaces/sequelize-orm-config.interface';
#Injectable()
export class ConfigService {
get sequelizeOrmConfig(): SequelizeOrmConfig {
return dbConfigData.databaseOpt;
}
get jwtConfig(): JwtConfig {
return {
jwtPrivateKey: config.jwtPrivateKey,
valideTime: config.valideTime,
};
}
}
You need to provide some value for Nest to inject for your UserRepository. It looks like you are using the TypeORM #InjectRepository() decorator, so in your testing module you'll need to add something like this under your providers
{
provide: getRepositoryToken('UsersRepository'),
useValue: MyMockUserRepo,
}
So that Nest can know what value to inject for that string. MyMockUserRepo would be your mock repository functionality, so that you aren't making actual database calls to your backend

Could not mock oracledb.getConnection() in jest unit test for nodejs typescript class that use oracledb npm

This is nodejs typescript class to execute query or getConnection using oracledb npm.
I could not mock oraclebd getConnection in jest unit test.
How to write unit test for executeQuery. It shows test coverage to be done on finally block all statement.
I written unit test but
import { Inject, Injectable } from '#nestjs/common';
import * as oracledb from 'oracledb';
import { ORACLE_DB_OPTIONS } from '../constant';
import { OracleDBOptions } from '../interface';
import { PromInstanceCounter, PromMethodCounter } from '#digikare/nestjs-prom';
#PromInstanceCounter
#Injectable()
export class OracleDBService {
constructor(
#Inject(ORACLE_DB_OPTIONS)
private readonly oracleDbOptions: OracleDBOptions[],
) { }
#PromMethodCounter()
async executeQuery(
dbName: string,
query: string,
bindValue: any[] = [],
) {
let localConnection: any;
try {
const oracleDbOption = this.oracleDbOptions.filter(
x => x.name === dbName,
);
if (!oracleDbOption) {
throw Error('Connection string does not exist');
}
localConnection = await oracledb.getConnection({
user: oracleDbOption[0].user,
password: oracleDbOption[0].password,
connectString: oracleDbOption[0].connectString,
});
const result = await localConnection.execute(query, bindValue);
await localConnection.close();
return result;
} finally {
if (localConnection) {
try {
await localConnection.close();
} catch (err) {
console.log('Error when closing the database connection: ', err);
}
}
}
}
#PromMethodCounter()
async getConnection(dbName: string) {
const oracleDbOption = this.oracleDbOptions.filter(x => x.name === dbName);
if (!oracleDbOption) {
throw Error('Connection string does not exist');
}
const localConnection = await oracledb.getConnection({
user: oracleDbOption[0].user,
password: oracleDbOption[0].password,
connectString: oracleDbOption[0].connectString,
});
return localConnection;
}
}
Written Unit Test for getConnection() method.
describe('OracleDbService', () => {
let oracleDBService: OracleDBService;
let oracleDBOptions = [
{
name: 'rfdest',
user: 'rfdest',
password: 'rfdest',
connectString: 'alsyntstb.ohlogistics.com:1521/syntstb',
},
{
name: 'DOCGENDEV',
user: 'DOCGENDEV',
password: 'DocGen$dev18',
connectString: 'alsynwebd.ohlogistics.com/synwebd_maint',
},
];
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
OracleDBService,
{
provide: ORACLE_DB_OPTIONS,
useValue: oracleDBOptions,
},
],
}).compile();
oracleDBService = module.get<OracleDBService>(OracleDBService);
});
it('should be defined', () => {
expect(oracleDBService).toBeDefined();
});
it('getConnection success', () => {
jest.fn(getConnection).mockReturnValue({
execute: function() {},
close: function() {},
});
oracleDBService.getConnection('rfdest').then(resolve => {
expect(resolve).not.toBeNull();
});
});
it('getConnection throw error', () => {
jest.fn(getConnection).mockReturnValue({
execute: function() {},
close: function() {},
});
oracleDBService
.getConnection('')
.then(resolve => {
expect(resolve).not.toBeNull();
})
.catch(reject => {
expect(reject).not.toBeNull();
});
});
});

Resources