not getting the object properties of a node object - javascript

so, i am very new to node and express, i ran through a problem like
here i am importing all other js files like
import { User } from './user.js';
class App {
constructor() {
this.init();
}
async init() {
this.user = await new User();
this.team = await new Team();
this.navbar = new Navbar();
this.tree = new Tree();
this.settings = await new Settings();
this.board = await new Board();
this.ping();
return this;
}
ping() {
//some functionality
}
}
now creating the object here
app = await new App();
console.log('app', app);
this gives me
app > App {}
on clicking the > i am getting this
>user: User {username: "someusername", roles: Array(1), settings: undefined}
>navbar: Navbar {timerIsRunning: false}
how can i access the properties like app.user also JSON.stringify gives me blank {}

Replace constructor in App class by next:
constructor() {
return (async () => {
return await this.init();
})();
}
now creating the object here
(async () => {
const app = await new App();
console.log("app", app);
})();

Related

Unable to mock a class method in Javascript/Typescript

I am not getting any clue how to mock a method. I have to write a unit test for this function:
index.ts
export async function getTenantExemptionNotes(platform: string) {
return Promise.all([(await getCosmosDbInstance()).getNotes(platform)])
.then(([notes]) => {
return notes;
})
.catch((error) => {
return Promise.reject(error);
});
}
api/CosmosDBAccess.ts
import { Container, CosmosClient, SqlQuerySpec } from "#azure/cosmos";
import { cosmosdbConfig } from "config/Config";
import { Workload } from "config/PlatformConfig";
import { fetchSecret } from "./FetchSecrets";
export class CosmoDbAccess {
private static instance: CosmoDbAccess;
private container: Container;
private constructor(client: CosmosClient) {
this.container = client
.database(cosmosdbConfig.database)
.container(cosmosdbConfig.container);
}
static async getInstance() {
if (!CosmoDbAccess.instance) {
try {
const connectionString = await fetchSecret(
"CosmosDbConnectionString"
);
const client: CosmosClient = new CosmosClient(connectionString);
// Deleting to avoid error: Refused to set unsafe header "user-agent"
delete client["clientContext"].globalEndpointManager.options
.defaultHeaders["User-Agent"];
CosmoDbAccess.instance = new CosmoDbAccess(client);
return CosmoDbAccess.instance;
} catch (error) {
// todo - send to app insights
}
}
return CosmoDbAccess.instance;
}
public async getAllNotesForLastSixMonths() {
const querySpec: SqlQuerySpec = {
// Getting data from past 6 months
query: `SELECT * FROM c
WHERE (udf.convertToDate(c["Date"]) > DateTimeAdd("MM", -6, GetCurrentDateTime()))
AND c.IsArchived != true
ORDER BY c.Date DESC`,
parameters: [],
};
const query = this.container.items.query(querySpec);
const response = await query.fetchAll();
return response.resources;
}
}
export const getCosmosDbInstance = async () => {
const cosmosdb = await CosmoDbAccess.getInstance();
return cosmosdb;
};
index.test.ts
describe("getExemptionNotes()", () => {
beforeEach(() => {
jest.resetAllMocks();
});
it("makes a network call to getKustoResponse which posts to axios and returns what axios returns", async () => {
const mockNotes = [
{
},
];
const cosmosDBInstance = jest
.spyOn(CosmoDbAccess, "getInstance")
.mockReturnValue(Promise.resolve(CosmoDbAccess.instance));
const kustoResponseSpy = jest
.spyOn(CosmoDbAccess.prototype, "getAllNotesForLastSixMonths")
.mockReturnValue(Promise.resolve([mockNotes]));
const actual = await getExemptionNotes();
expect(kustoResponseSpy).toHaveBeenCalledTimes(1);
expect(actual).toEqual(mockNotes);
});
});
I am not able to get instance of CosmosDB or spyOn just the getAllNotesForLastSixMonths method. Please help me code it or give hints. The complexity is because the class is singleton or the methods are static and private

How to synchronize a method in javascript?

I am trying to synchronise a singleton.
I would need to make this method like the equivalent of synchronized in java.
What happens to me is that because the socket takes a while, if the first two requests are very close together I get two websockets created. (Then from the third one onwards it takes the instance correctly).
import io from 'socket.io-client';
export default class SocketIo {
static socket = null;
static instance = null;
async initialize() {
this.socket = await io(`http://${ip}:10300/`, {
transports: ['websocket'],
});
}
static async getInstance() {
logger.info('socketIo.api.getInstance: BEGIN');
if (!this.instance) {
logger.info('socketIo.api.getInstance: creating new socket instance...');
try {
const o = new SocketIo();
await o.initialize();
this.instance = o;
logger.info('socketIo.api.getInstance: socket instance created SUCCESSFULLY');
} catch (e) {
moaLog('socketIo.api.getInstance: ERROR: ', e);
throw e;
}
} else {
logger.info('socketIo.api.getInstance: a socket instance already exists, reusing that one');
}
logger.info('socketIo.api.getInstance: END');
return this.instance;
}
}
in main.js
var socket1 = SocketIo.getInstance();
var socket2 = SocketIo.getInstance();
// ... after a while
var socket3 = SocketIo.getInstance();
2022-06-16T17:53:40.658Z: socketIo.api.getInstance: BEGIN
2022-06-16T17:53:40.660Z: socketIo.api.getInstance: creating new socket instance...
2022-06-16T17:53:41.140Z: socketIo.api.getInstance: BEGIN
2022-06-16T17:53:41.141Z: socketIo.api.getInstance: creating new socket instance...
2022-06-16T17:53:41.379Z: socketIo.api.getInstance: socket instance created SUCCESSFULLY
2022-06-16T17:53:41.382Z: socketIo.api.getInstance: END
2022-06-16T17:53:41.411Z: socketIo.api.getInstance: socket instance created SUCCESSFULLY
2022-06-16T17:53:41.415Z: socketIo.api.getInstance: END
...
2022-06-16T17:56:13.076Z: socketIo.api.getInstance: BEGIN
2022-06-16T17:56:13.078Z: socketIo.api.getInstance: a socket instance already exists, reusing that one
2022-06-16T17:56:13.079Z: socketIo.api.getInstance: END
And from server view I see two websocket connections.
Any ideas?
Below is an attempt to synchronize your singleton. The idea is to store the o.intitialize promise and check if it already has been acquired before.
I added an uid, a random value set in initialize to show that only single instance is created.
class SocketIo {
static instance = null;
static _lock = null;
async initialize() {
this.uid = Math.random();
}
static async getInstance() {
console.log('socketIo.api.getInstance: BEGIN');
if (!this.instance) {
console.log('socketIo.api.getInstance: creating new socket instance...');
const o = new SocketIo();
if (!this._lock) {
this._lock = o.initialize();
await this._lock;
this.instance = o;
console.log('socketIo.api.getInstance: socket instance created SUCCESSFULLY');
this._lock = null;
} else {
await this._lock;
}
}
console.log('socketIo.api.getInstance: END');
return this.instance;
}
}
async function Main() {
var socket1 = SocketIo.getInstance();
var socket2 = SocketIo.getInstance();
console.log((await socket1).uid);
console.log((await socket2).uid);
}
Main()
Compare it to your version:
class SocketIo {
static instance = null;
async initialize() {
this.uid = Math.random();
}
static async getInstance() {
console.log('socketIo.api.getInstance: BEGIN');
if (!this.instance) {
console.log('socketIo.api.getInstance: creating new socket instance...');
const o = new SocketIo();
await o.initialize();
this.instance = o;
console.log('socketIo.api.getInstance: socket instance created SUCCESSFULLY');
}
console.log('socketIo.api.getInstance: END');
return this.instance;
}
}
async function Main() {
var socket1 = SocketIo.getInstance();
var socket2 = SocketIo.getInstance();
console.log((await socket1).uid);
console.log((await socket2).uid);
}
Main()
Hope this is what suits you.
I solved using async-lock.
import AsyncLock from 'async-lock';
const lock = new AsyncLock();
export default class SocketIo {
// ...
static async getInstance() {
logger.info('socketIo.api.getInstance: BEGIN');
if (!this.instance) {
logger.info('socketIo.api.getInstance: creating new socket instance...');
try {
await lock.acquire('socketIo', async () => {
if (!this.instance) {
const o = new SocketIo();
await o.initialize();
this.instance = o;
logger.info('socketIo.api.getInstance: socket instance created SUCCESSFULLY');
}
});
} catch (e) {
moaLog('socketIo.api.getInstance: ERROR: ', e);
throw e;
}
} else {
logger.info('socketIo.api.getInstance: a socket instance already exists, reusing that one');
}
logger.info('socketIo.api.getInstance: END');
return this.instance;
}
}

Why cannot read instance when unit testing?

*This app is for practice only.
I am trying to create multiple classes here that make up a chat room.
I create app instance as singleton instance.
App instance basically work as single module where it stores all users and rooms of the chat app.
This is what app instance looks like.
class App {
constructor() {
this.users = [];
this.rooms = [];
}
addUser(user) {
const duplicateUser = this.users.find(
(appUser) => appUser.userName === user.userName
);
if (duplicateUser) {
throw new Error("User already exists.");
}
this.users.push(user);
}
createUser(userName) {
const newUser = new User(userName);
this.addUser(newUser);
return newUser;
}
getUser(userName) {
return this.users.find((user) => user === userName);
}
....
}
const app = new App();
// Object.freeze(app); Commented out for testing purpose.
class User {
constructor(userName) {
this.userName = userName;
this.joinedRoomName = null;
}
createRoom(roomName) {
const duplicateRoom = app.getRoom(roomName);
const duplicateUser = app.getUser(this.userName);
if (duplicateRoom) {
throw new Error("The room already exists.");
}
if (duplicateUser) {
throw new Error("The user is already in another room");
}
const host = new Host(this.userName);
const room = new Room(roomName, host);
app.addRoom(room);
return room;
}
...other methods
I added a new user instance by using createUser above in the App.
When user creates an instance called room, as defined in user method,
it uses app's method(not static, but imported the instance) "getRoom and getUser".
However I get reference error like so:
TypeError: Cannot read property 'getRoom' of undefinedJest
Below is my jest code.
What is the issue here?
beforeEach(() => app.reset());
describe("클래스 인스턴스 생성 테스트", () => {
it("app 은 App 의 인스턴스여야 합니다.", () => {
expect(app).toBeInstanceOf(App);
});
it("App 에서 새로운 유저를 만들었을 때 앱에 해당 유저가 등록되어야 합니다.", () => {
const testUser = app.createUser("test");
expect(testUser.userName).toEqual(app.users[0].userName);
});
});
describe("방 개설과 방 참여 테스트", () => {
it("방을 개설했을 때 방은 App 에 추가되어야 합니다.", () => {
app.createUser("test");
const testUser = app.users[0];
const testRoom = testUser.createRoom("testRoom");
expect(testRoom.roomName).toEqual(app.rooms[0].roomName);
});
it("방 개설을 했을 때 그 방의 호스트는 개설한 유저 자신이어야 합니다.", () => {});
it("방 참여를 한다면 앱의 방에 해당 유저가 추가되어 있어야 합니다.", () => {});
it("다른 방에 속해있는 유저는 새로운 방을 개설할 수 없습니다.", () => {});
it("다른 방에 속해있는 유저는 새로운 방에 참여할 수 없습니다.", () => {});
it("사용자는 대화방을 나갈 수 있어야 합니다.", () => {});
});

Why does a unit test with sinon createStubInstance is successful but hangs?

I'm unit testing a method in fileA.js that requires a new class instance from fileB.js with success.
The problem is that I get success, as expected but this specific test hangs and I don't get results from istanbul.
Yes, I have already added --exit flag. This only happens if I run this test... Why does it hang?
This is the method in fileA.js:
global.mapperObj = {};
const opts = config.opts
(...)
async function startServices() {
const data = await getData();
Object.keys(data).forEach(function(key) {
mapperObj[key] = new ClassInFileB(key, data[key], opts);
mapperArray.push(key);
});
}
The class in fileB.js:
const npmPool = require('npmPackage');
class ClassInFileB{
constructor(ip, port, opts) {
this.classPool = npmPool.createPool(ip, port, opts);
}
(...)
// other class methods
}
And the test for that method:
const rewire = require('rewire');
const fileA = rewire(`path/to/fileA`);
const ClassInFileB = require(`path/to/fileB`);
describe('Testing startServices() function', function () {
it('It should not throw errors', async function () {
let result;
let error = false;
global.mapperArray = [];
try {
function getDataMock() {
return { '0.0.0.1': 'thisIsSomething'};
}
fileA.__set__('getData', getDataMock);
// Create a stub instance to ClassInFileB class avoiding the constructor
sinon.createStubInstance(ClassInFileB);
result = await fileA.startServices();
} catch (err) {
error = err;
}
expect(error).to.be.false;
});

Cannot call save() in ES6 mongoose extended model

Im trying to extend a Mongoose Model using ES6 syntax. While I can call successfully find({}) to retrieve data from mongo database, I am not able to call save() to save data. Both are executed inside the Model.
The error returned is Error: TypeError: this.save is not a function
const mongoose = require('mongoose')
const {Schema, Model} = mongoose
const PersonSchema = new Schema(
{
name: { type: String, required: true, maxlength: 1000 }
},
{ timestamps: { createdAt: 'created_at', updatedAt: 'update_at' } }
)
class PersonClass extends Model {
static getAll() {
return this.find({})
}
static insert(name) {
this.name = 'testName'
return this.save()
}
}
PersonSchema.loadClass(PersonClass);
let Person = mongoose.model('Persons', PersonSchema); // is this even necessary?
(async () => {
try {
let result = await Person.getAll() // Works!
console.log(result)
let result2 = await Person.insert() // FAILS
console.log(result2)
} catch (err) {
throw new Error(err)
}
})()
Im using:
Nodejs 7.10
mongoose 5.3.15
This is normal. You're trying to access a non static method from a static method.
You need to do something like this:
static insert(name) {
const instance = new this();
instance.name = 'testName'
return instance.save()
}
Some working example:
class Model {
save(){
console.log("saving...");
return this;
}
}
class SomeModel extends Model {
static insert(name){
const instance = new this();
instance.name = name;
return instance.save();
}
}
const res = SomeModel.insert("some name");
console.log(res.name);
Here is an example of what works and what doesn't work.
class SomeParentClass {
static saveStatic(){
console.log("static saving...");
}
save(){
console.log("saving...");
}
}
class SomeClass extends SomeParentClass {
static funcStatic(){
this.saveStatic();
}
func(){
this.save();
}
static funcStaticFail(){
this.save();
}
}
//works
SomeClass.funcStatic();
//works
const sc = new SomeClass();
sc.func();
//fails.. this is what you're trying to do.
SomeClass.funcStaticFail();

Categories

Resources