i have to clone node modesl module to make it work in a class or function - node.js

i'm writing a nodejs class to play with modesl ( freswitch events module )
'use strict';
const esl = require('modesl');
class eslClass {
connect() {
this.fswcon = new esl.Connection(config.fswEslHost, config.fswEslPort, 'ClueCon', () => {
this._listen();
});
}
}
// connect() will failed with a 'this.once' is undefined ( .once is coming from eventEmitter2, i believe )
i've to 'clone' object to cancel error
const eslClone = esl.Connection;
class eslClass {
connect() {
this.fswcon = new eslClone (config.fswEslHost, config.fswEslPort, 'ClueCon', () => {
this._listen();
});
}
}
// error is gone away !!

Related

How test listener on my custom event emitter in node typescript

I'm trying to test a service that has a listener of the a custom Event Emitter in node with typescript and mocha, sinon.
My custom emmiter;
class PublishEmitter extends EventEmitter {
publish(id: string) {
this.emit('publish', id);
}
}
My service use case:
export default class PublishVehicle {
constructor(
private findVehicle: FindVehicle, // Service that contains find methods on repository
private updateVehicle: UpdateVehicle, // Service that contains update methods on repository
private logger: ILogger,
) {
this.producer = producer;
this.logger = logger;
}
listen() {
this.logger.log('debug', 'Creating listener on PublishEmitter');
this.publishListener = this.publishListener.bind(this);
pubsub.on('publish', this.publishListener);
}
/**
* Listener on PublishEmitter.
*
* #param event
*/
async publishListener(event: string) {
try {
const vehicle = await this.findVehicle.findById(event);
if (vehicle?.state === State.PENDING_PUBLISH) {
//
const input = { state: State.PUBLISH };
await this.updateVehicle.update(vehicle.id, input);
this.logger.log('debug', `Message sent at ${Date.now() - now} ms`);
}
this.logger.log('debug', `End Vehicle's Publish Event: ${event}`);
} catch (error) {
this.logger.log('error', {
message: `publishListener: ${event}`,
stackTrace: error,
});
}
}
}
and in my test file:
import chai from 'chai';
const { expect } = chai;
import sinon from 'sinon';
import { StubbedInstance, stubInterface } from 'ts-sinon';
import pubsub from './PublishEmitter';
describe('Use Case - Publish Vehicle', function () {
let mockRepository: MockVehicleRepository;
let publishVehicle: PublishVehicle;
let findVehicleUseCase: FindVehicle;
let updateVehicleUseCase: UpdateVehicle;
before(() => {
const logger = Logger.getInstance();
mockRepository = new MockVehicleRepository();
findVehicleUseCase = new FindVehicle(mockRepository, logger);
updateVehicleUseCase = new UpdateVehicle(mockRepository);
publishVehicle = new PublishVehicle(
findVehicleUseCase,
updateVehicleUseCase,
logger,
);
});
afterEach(() => {
// Restore the default sandbox here
sinon.restore();
});
it('Should emit event to publish vehicle', async () => {
const vehicle = { ... }; // dummy data
const stubFindById = sinon
.stub(mockRepository, 'findById')
.returns(Promise.resolve(vehicle));
const stubUpdate = sinon
.stub(mockRepository, 'update')
.returns(Promise.resolve(vehicle));
const spy = sinon.spy(publishVehicle, 'publishListener');
publishVehicle.listen();
pubsub.publish(vehicle.id);
expect(spy.calledOnce).to.be.true; // OK
expect(stubFindById.calledOnce).to.be.true; // Error (0 call)
expect(stubUpdate.calledOnce).to.be.true; // Error (0 call)
});
});
When I debug this test, indeed the methods are called but they seem to be executed after it has gone through the last expect lines.
The output:
1 failing
1) Use Case - Publish Vehicle
Should emit event to publish vehicle:
AssertionError: expected false to be true
+ expected - actual
-false
+true
UPDATE
Finally I was be able to solve my problem wrapping expect lines in setTimeout.
setTimeout(() => {
expect(spy.calledOnce).to.be.true; // OK
expect(stubFindById.calledOnce).to.be.true; // OK
expect(stubUpdate.calledOnce).to.be.true; // OK
done();
}, 0);

React and Easybase - Invalid hook call. Hooks can only be called inside of the body of a function component

I am trying to use React and Easybase (database). I'm having some issues however.
This is in the SolanaSignature.tsx file.
import { useWallet } from '#solana/wallet-adapter-react';
import bs58 from 'bs58';
import React, { FC, useCallback } from 'react';
import ReactDOM from 'react-dom';
import { sign } from 'tweetnacl';
import AddUser from './mainstorage';
export const SignMessageButton : FC = () => {
const { publicKey, signMessage } = useWallet();
const onClick = useCallback(async () => {
try {
if (!publicKey) throw new Error('Wallet not connected!');
if (!signMessage) throw new Error('Wallet does not support message signing! Please use a wallet such as Phantom or Solflare! NOTE: Some Ledgers wallets are not supported!');
const message = new TextEncoder().encode('Omega Protocol - Signature verification for Bold Badgers.');
const signature = await signMessage(message);
if (!sign.detached.verify(message, signature, publicKey.toBytes())) throw new Error('Invalid signature!');
//alert(`Message signature: ${bs58.encode(signature)}`);
AddUser();
} catch (error: any) {
alert(`Signing failed: ${error?.message}`);
}
}, [publicKey, signMessage]);
return signMessage ? (<button className="wallet-adapter-button wallet-adapter-button-trigger shine" onClick={onClick} disabled={!publicKey}>Verify</button>) : null;
};
and then the mainstorage file:
import { useEffect } from 'react';
import { useEasybase } from 'easybase-react';
const AddUser = () => {
const { db } = useEasybase();
useEffect(() => {
db('OMEGABB').insert({ walletid: "test", discordid: "test", signature: "test", valid: false, lastvalid: new Date() }).one()
.then(() => console.log("Success!"));
}, [])
return (
{/* ... */}
);
}
export default AddUser;
What is happening however when I click the button is that it comes up with a warning: Hooks can only be called inside the body of a function component.
This does work in the initial index file (aka the parent file) but does not work here. Right now this is only a dummy/test but trying to get it writing to the database.
Thanks!
As per React's documentation:
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns.
Currently, you're attempting to call a hook inside the onClick handler - AddUser is a custom hook since it also uses hooks and the better name for it should be useAddUser.
I suggest to make some improvements by returning a function from your custom hook that you can call to add a new user, e.g.:
export const useAddUser = () => {
const {db} = useEasybase()
const addUser = React.useCallback(() => {
db('OMEGABB')
.insert(/*...*/)
.then(/*...*/)
.catch(/*...*/)
}, [db])
return {
addUser,
/*...*/
}
}
Then, you can use useAddUser in the following way:
const {useAddUser} from './mainstorage'
const SignMessageButton: FC = () => {
const {publicKey, signMessage} = useWallet()
const {addUser} = useAddUser();
const onClick = React.useCallback(
async () => {
try {
// ...
addUser()
} catch (error) {/*...*/}
},
[publicKey, signMessage, addUser]
)
/*...*/
}

can't get the Jest provided ESM example to run

I'm just trying to get the ES6 Class Mocks example provided by Jest to run green.
here's my code repo
it's taken me way to long to even get to this point, but the tests still fail with
TypeError: SoundPlayer.mockClear is not a function
system under test
import SoundPlayer from './sound-player';
export default class SoundPlayerConsumer {
constructor() {
this.soundPlayer = new SoundPlayer();
}
playSomethingCool() {
const coolSoundFileName = 'song.mp3';
this.soundPlayer.playSoundFile(coolSoundFileName);
}
}
the test
import {jest} from '#jest/globals';
import SoundPlayer from './sound-player';
import SoundPlayerConsumer from './sound-player-consumer';
const mockPlaySoundFile = jest.fn();
jest.mock('./sound-player', () => {
return jest.fn().mockImplementation(() => {
return {playSoundFile: mockPlaySoundFile};
});
});
beforeEach(() => {
SoundPlayer.mockClear();
mockPlaySoundFile.mockClear();
});
it('The consumer should be able to call new() on SoundPlayer', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
// Ensure constructor created the object:
expect(soundPlayerConsumer).toBeTruthy();
});
it('We can check if the consumer called the class constructor', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
expect(SoundPlayer).toHaveBeenCalledTimes(1);
});
it('We can check if the consumer called a method on the class instance', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
const coolSoundFileName = 'song.mp3';
soundPlayerConsumer.playSomethingCool();
expect(mockPlaySoundFile.mock.calls[0][0]).toEqual(coolSoundFileName);
});
system under test dependency
export default class SoundPlayer {
constructor() {
this.foo = 'bar';
}
playSoundFile(fileName) {
console.log('Playing sound file ' + fileName);
}
}

How to cover arrow functions in unit testing in angular?

this.service = () => { -- statements -- }
The above statement is to be tested using jasmine unit testing in angular.
Can i get some suggestions for that ?
it("should service call",()=>{ // i want to call the arrow function here like component.service.? what to use in place of '?'. })
It is a function so you call it immediately:
example:
interface Service {
fun: () => string;
}
class Component {
constructor() {
this.service = () => {
return {
fun: () => 'hello'
};
};
}
service: () => Service;
}
Calling it:
const component = new Component();
const service = component.service();
const message = service.fun();
// or in one line:
const message = new Component().service().fun();
Typescript playground example

How do you generate typings for protobuf files for use with GRPC?

I am trying to use GRPC with TypeScript, and I am trying to make sure I have all the types set (rather than just adding my own mapping or using any.
I've gotten as far as with problems I am experiencing noted in the comments.
import { Server, loadPackageDefinition } from "grpc";
import { loadSync } from "#grpc/proto-loader";
const packageDefinition = loadSync(__dirname + "/protos/artifact.proto");
const artifacts = loadPackageDefinition(packageDefinition).artifacts;
// what are the types here?
function SignedUrlPutObject(call, callback) {
}
const server = new Server();
// There's no ArtifactUpload defined in artifacts
server.addService(artifacts.ArtifactUpload.service, { SignedUrlPutObject })
Another approach I tried was to use pbjs and pbts.
"protobuf": "pbjs -t static-module -w commonjs -o protos.js protos/artifact-upload.proto && pbts -o protos.d.ts protos.js",
This generated the typings file, but I can't get it to work with grpc. Here's a github issue I found that may be related https://github.com/protobufjs/protobuf.js/issues/1381
There's 3 main tools you can use:
ts-protoc-gen
#grpc/proto-loader
grpc_tools_node_protoc_ts
I recommend using proto-loader:
npm i #grpc/proto-loader
You can then generate the types like so:
./node_modules/.bin/proto-loader-gen-types --longs=String --enums=String --defaults --oneofs --grpcLib=#grpc/grpc-js --outDir=proto/ proto/*.proto
Here's the proto file I use for this example:
syntax = "proto3";
package example_package;
message ServerMessage {
string server_message = 1;
}
message ClientMessage {
string client_message = 1;
}
service Example {
rpc unaryCall(ClientMessage) returns (ServerMessage) {}
rpc serverStreamingCall(ClientMessage) returns (stream ServerMessage) {}
rpc clientStreamingCall(stream ClientMessage) returns (ServerMessage) {}
rpc bidirectionalStreamingCall(stream ClientMessage) returns (stream ServerMessage) {}
}
Once the types are generated, you can consume them like so:
import * as grpc from '#grpc/grpc-js';
import * as protoLoader from '#grpc/proto-loader';
import { ProtoGrpcType } from './proto/example';
import { ClientMessage } from './proto/example_package/ClientMessage';
import { ExampleHandlers } from './proto/example_package/Example';
import { ServerMessage } from './proto/example_package/ServerMessage';
const host = '0.0.0.0:9090';
const exampleServer: ExampleHandlers = {
unaryCall(
call: grpc.ServerUnaryCall<ClientMessage, ServerMessage>,
callback: grpc.sendUnaryData<ServerMessage>
) {
if (call.request) {
console.log(`(server) Got client message: ${call.request.clientMessage}`);
}
callback(null, {
serverMessage: 'Message from server',
});
},
serverStreamingCall(
call: grpc.ServerWritableStream<ClientMessage, ServerMessage>
) {
call.write({
serverMessage: 'Message from server',
});
},
clientStreamingCall(
call: grpc.ServerReadableStream<ClientMessage, ServerMessage>
) {
call.on('data', (clientMessage: ClientMessage) => {
console.log(
`(server) Got client message: ${clientMessage.clientMessage}`
);
});
},
bidirectionalStreamingCall(
call: grpc.ServerDuplexStream<ClientMessage, ServerMessage>
) {
call.write({
serverMessage: 'Message from server',
});
call.on('data', (clientMessage: ClientMessage) => {
console.log(
`(server) Got client message: ${clientMessage.clientMessage}`
);
});
},
};
function getServer(): grpc.Server {
const packageDefinition = protoLoader.loadSync('./proto/example.proto');
const proto = (grpc.loadPackageDefinition(
packageDefinition
) as unknown) as ProtoGrpcType;
const server = new grpc.Server();
server.addService(proto.example_package.Example.service, exampleServer);
return server;
}
if (require.main === module) {
const server = getServer();
server.bindAsync(
host,
grpc.ServerCredentials.createInsecure(),
(err: Error | null, port: number) => {
if (err) {
console.error(`Server error: ${err.message}`);
} else {
console.log(`Server bound on port: ${port}`);
server.start();
}
}
);
}
I've created various examples of how to use gRPC with TypeScript here: https://github.com/badsyntax/grpc-js-types

Resources