I'm developing NestJS app which asks Binance Websocket API for some data. And also created a WebSocket server that sends received data to Front. On the Back side I got all data in console.log. But on the Front I got only the first item. I can't understand what's wrong. Can you help me please?
Coin.gateway.ts
import { MessageBody, SubscribeMessage, WebSocketGateway, WebSocketServer } from '#nestjs/websockets';
import { Server } from 'socket.io';
import { from, of, take, map, Observable } from 'rxjs';
import { Coin } from './classes/coin';
import * as coinlist from './list/coins.json'
#WebSocketGateway(811, {transports: ['websocket', 'polling'], cors: true})
export class CoinGateway {
#WebSocketServer()
server: Server;
#SubscribeMessage('events')
handleMessage(#MessageBody() data: any) {
console.log('data',data)
const coins = new Coin(coinlist, 'usdt', 'miniTicker')
return coins.getCryptoData().pipe(map((c) => {
return c
}))
}
}
Coin.ts
import { GetCryptocurrencies } from "./abstract/get-cryptocurrencies";
import { WebSocket } from "ws";
import { Logger } from "#nestjs/common";
import { Observable } from "rxjs";
export class Coin extends GetCryptocurrencies {
private readonly logger = new Logger(Coin.name)
private baseUrl: string
private url: string
constructor(coin: { name: string, symbol: string }[], pair: string, method: string) {
super(coin, pair, method)
this.baseUrl = 'wss://stream.binance.com:9443/stream?streams='
this.url = coin.map((c) => {
return `${c.symbol.toLowerCase()}${pair}#${method}`
}).join('/')
}
getCryptoData(): any {
const stream$ = new Observable((observer) => {
const ws = new WebSocket(`${this.baseUrl}${this.url}`)
ws.on('open', () => {
this.logger.log('Connection established')
})
ws.onmessage = (msg: any) => {
const message = JSON.parse(msg.data)
observer.next(message)
}
ws.on('close', () => {
this.logger.log('Connection closed')
})
})
return stream$
}
}
Client UI useEffect hook
useEffect(() => {
const socket = io('ws://localhost:811', {transports: ['websocket']})
socket.on('connect', () => {
console.log('Connection established from client')
socket.emit('events', '', (res: any) => {
console.log(res)
})
const engine = socket.io.engine;
console.log(engine.transport.name); // in most cases, prints "polling"
engine.once("upgrade", () => {
// called when the transport is upgraded (i.e. from HTTP long-polling to WebSocket)
console.log(engine.transport.name); // in most cases, prints "websocket"
});
engine.on("packetCreate", ({ type, data }) => {
// called for each packet sent
console.log('Stype', type)
console.log('Sdata', data)
});
})
}, [])
Okay after some hours of researching and I learned that I need just to return this:
return coins.getCryptoData().pipe(map((c) => {
this.server.emit('msg', c)
}))
And receive this message on Front
Related
I am attaching all the function snippets below. I am using jest to run a unit test on this function but this needs to mock axios. I tried like this :
// TODO - mock axios class instance for skipped Test suites
describe("dateFilters()", () => {
beforeEach(() => {
jest.resetAllMocks();
});
it("Mock Fetch API for Date Options Response", async () => {
const mockFn = jest.fn();
setUpMockResponse(mockFn, mockFetchDateOptionsResponse);
const response = await dateFilters(Workload.WIN32);
expect(mockFn).toHaveBeenCalledTimes(1);
expect(response?.data).toEqual(mockFetchDateOptionsResponse);
});
});
The error I am getting is :
thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
It seems it is not mocking anything.
All the require function definitons are below:
export const dateFilters = async (platform) => {
const dates = await getKustoResponse({
queryName: platform.toLowerCase().concat("DateFilters"),
platform,
queryParams: {},
});
return dates;
};
export const getKustoResponse = async ({
queryName,
platform,
queryParams,
cluster = "Default",
}: QueryDetail) => {
const dbName = getClusterValue({ platform, cluster, key: "db" });
const url = getClusterValue({ platform, cluster, key: "kustoUrl" });
const postBody = {
db: dbName,
csl: queryParams
? substituteQueryParameters(queries[queryName], queryParams)
: queries[queryName],
};
const apiClient = ApiClient.getInstance();
const response = await apiClient.post(url, postBody, {
headers: {
...kustoApiRequestDefaultConfiguration.headers,
"x-ms-kql-queryName": queryName,
},
timeout: kustoApiRequestDefaultConfiguration.timeout,
});
return response;
};
import Axios, { AxiosInstance } from "axios";
import axiosRetry from "axios-retry";
export class ApiClient {
private static instance: AxiosInstance;
public static getInstance = (): AxiosInstance => {
if (!ApiClient.instance) {
ApiClient.createInstance();
}
return ApiClient.instance;
};
private constructor() {
ApiClient.getInstance();
}
protected static createInstance = () => {
const responseType = "json";
const client = Axios.create({
responseType,
});
axiosRetry(client, apiRetryConfiguration);
client.interceptors.request.use(requestInterceptor);
client.interceptors.response.use(responseInterceptor, errorInterceptor);
ApiClient.instance = client;
};
}
export const requestInterceptor = async (
request: AxiosRequestConfig
): Promise<AxiosRequestConfig> => {
const token = await getKustoToken();
request.headers = { ...request.headers, Authorization: `Bearer ${token}` };
return request;
};
There is no fetch call in your source code. Is it in the apiClient? If so, do this:
jest.spyOn(apiClient, 'post').mockImplementation();
expect(apiClient.post).toHaveBeenCalled();
I am not sure I how to write unit test case file for guard in nestjs. I have below Role.guard.ts file. I have to create Role.guard.spec.ts file. can somebody help please?
import { Injectable, CanActivate, ExecutionContext, Logger } from '#nestjs/common';
import { Reflector } from '#nestjs/core';
import { ROLES_KEY } from './roles.decorator';
import { Role } from './role.enum';
#Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
const { user } = context.switchToHttp().getRequest();
if (!user.role) {
Logger.error('User does not have a role set');
return false;
}
if (user.role === Role.Admin) {
return true;
}
if (!Array.isArray(requiredRoles) || !requiredRoles.length) {
// No #Roles() decorator set, deny access as not admin
return false;
}
if (requiredRoles.includes(Role.All)) {
return true;
}
return requiredRoles.includes(user.role);
}
}
I wrote below code but coverage issue is coming.
import { createMock } from '#golevelup/ts-jest';
import { ExecutionContext } from "#nestjs/common";
import { Reflector } from "#nestjs/core";
import { RolesGuard } from "./roles.guard";
describe('RolesGuard', () => {
let guard: RolesGuard;
let reflector: Reflector;
beforeEach(() => {
reflector = new Reflector();
guard = new RolesGuard(reflector);
});
it('should be defined', () => {
expect(guard).toBeDefined();
});
it('should return false if user does not exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
const context = createMock<ExecutionContext>();
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(false);
})
})
below lines are not getting covered.
if (user.role === Role.Admin) {
return true;
}
if (!Array.isArray(requiredRoles) || !requiredRoles.length) {
// No #Roles() decorator set, deny access as not admin
return false;
}
if (requiredRoles.includes(Role.All)) {
return true;
}
return requiredRoles.includes(user.role);
Edit 1:-
Below test cases are covering my some part of code.
it('should return true if user exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
const context = createMock<ExecutionContext>({
switchToHttp: () => ({
getRequest: () => ({
user: {
role:'admin'
}
}),
}),
});
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(true);
})
it('should return false if user does not exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
const context = createMock<ExecutionContext>({
switchToHttp: () => ({
getRequest: () => ({
user: {
role:'user'
}
}),
}),
});
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(false);
})
But below code still not getting covered.
if (requiredRoles.includes(Role.All)) {
return true;
}
return requiredRoles.includes(user.role);
}
Can sombody help me on the same?
Looks like you need to be able to craft the payload appropriately such that your code is hit. There are a variety of ways to do this but, in a "Nest"-y way, we can try something like what the docs tell us. Notice in that link that the provided testing utilities make this a lot easier to mock.
import { createMock } from '#golevelup/ts-jest';
import { ExecutionContext } from "#nestjs/common";
import { Reflector } from "#nestjs/core";
import { RolesGuard } from "./roles.guard";
describe('RolesGuard', () => {
let guard: RolesGuard;
let reflector: Reflector
beforeEach(async () => {
reflector = new Reflector();
guard = new RolesGuard(reflector);
});
it('should be defined', () => {
expect(guard).toBeDefined();
});
it('should return false if user does not exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
const context = createMock<ExecutionContext>();
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(false);
})
it('should return false if user does exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
// Mock the "class" type of this so we can get what we want.
// We want to tell it to return an object where role is defined.
const context = createMock<ExecutionContext>({
switchToHttp: () => ({
getRequest: () => ({
user: { role: { /* enter your data here */ }
}),
}),
});
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(false);
})
})
From here your context is successfully hydrated with whatever you want and the second test should start showing up as covering your other code branches. You can now edit the role attribute to look however you want. Notice also in the above beforeEach call you should be able to switch to using testing modules instead. This is not exhaustive though, you'll likely need to add additional test cases to cover your other branches. If you follow as I've done here, that should be relatively trivial.
Does what I've done here make sense? By crafting a custom payload to the object, the roles attribute is present, allowing the test to evaluate other cases. I got my override from the createMock function directly from the docs for golevelup.
I am trying to test an axios request, and I need to use an auth token in order to access the endpoint, however my test fails because I am getting "Bearer null" and inputting this into my headers.Authorization. Here is my actual code below
File I'm testing:
this.$axios.get(url, { headers: { Authorization: `Bearer ${localStorage.getItem("access-token")}` } })
.then((response) => {
this.loading = true;
// Get latest barcode created and default it to our "from" input
this.barcodeFrom = response.data.data[response.data.data.length - 1]['i_end_uid'] + 1;
this.barcodeTo = this.barcodeFrom + 1;
this.barcodeRanges = response.data.data;
// Here we add to the data array to make printed barcodes more obvious for the user
this.barcodeRanges.map(item => item['range'] = `${item['i_start_uid']} - ${item['i_end_uid']}`);
// Make newest barcodes appear at the top
this.barcodeRanges.sort((a, b) => new Date(b['created_at']) - new Date(a['created_at']));
})
.catch((error) => {
console.log('Barcode retrieval error:', error);
this.barcodeFrom === 0 ? null : this.snackbarError = true;
})
.finally(() => {
// Edge case when there's no barcode records
this.barcodeFrom === 0 ? this.barcodeTo = 1 : null;
this.loading = false
});
console.log('bcr', this.barcodeRanges);
Test file:
import Vuetify from "vuetify";
import Vuex from "vuex";
import { createLocalVue, shallowMount } from "#vue/test-utils";
import VueMobileDetection from "vue-mobile-detection";
import axios from 'axios';
import index from "#/pages/barcode_logs/index";
describe('/pages/barcode_logs/index.vue', () => {
// Initialize our 3rd party stuff
const localVue = createLocalVue();
localVue.use(Vuetify);
localVue.use(Vuex);
localVue.use(axios);
localVue.use(VueMobileDetection);
// Initialize store
let store;
// Create store
store = new Vuex.Store({
modules: {
core: {
state: {
labgroup:{
current: {
id: 1
}
}
}
}
}
});
// Set-up wrapper options
const wrapperOptions = {
localVue,
store,
mocks: {
$axios: {
get: jest.fn(() => Promise.resolve({ data: {} }))
}
}
};
// Prep spies for our component methods we want to validate
const spycreateBarcodes = jest.spyOn(index.methods, 'createBarcodes');
const createdHook = jest.spyOn(index, 'created');
// Mount the component we're testing
const wrapper = shallowMount(index, wrapperOptions);
test('if barcode logs were retrieved', () => {
expect(createdHook).toHaveBeenCalled();
expect(wrapper.vm.barcodeRanges).toHaveLength(11);
});
});
How do I mock or get the actual auth token in to work in my test?
const setItem = jest.spyOn(Storage.prototype, 'setItem')
const getItem = jest.spyOn(Storage.prototype, 'getItem')
expect(setItem).toHaveBeenCalled()
expect(getItem).toHaveBeenCalled()
You can try to mock localStorage before creating instance of a wrapper like this:
global.localStorage = {
state: {
'access-token': 'superHashedString'
},
setItem (key, item) {
this.state[key] = item
},
getItem (key) {
return this.state[key]
}
}
You can also spy on localStorage functions to check what arguments they were called with:
jest.spyOn(global.localStorage, 'setItem')
jest.spyOn(global.localStorage, 'getItem')
OR
You can delete localVue.use(axios) to let your $axios mock work correctly.
This
mocks: {
$axios: {
get: jest.fn(() => Promise.resolve({ data: {} }))
}
}
is not working because of that
localVue.use(axios)
I am using the link below for implementing SignalR within react
ASP NET Core Signal R Tutorial
However, this code appears to not follow the current standards and #aspnet/signalr-client has now been marked as obselete with a message saying that #aspnet/signalr must be used
I managed to figure out that the accepted way for creating a hub connection is
// create the connection instance
var hubConnection = new signalR.HubConnectionBuilder()
.withUrl("URL", options)
.withHubProtocol(protocol)
.build();
HOwever, I dont know how to call this within react?
I tried
import signalR, {} from '#aspnet/signalr';
but that gives the error
./src/components/widgets/Chat.js
Attempted import error: '#aspnet/signalr' does not contain a default export (imported as 'signalR').
Does anyone have an updated sample for Signal R with react or know how to do this now?
The package wont install as its obselete
Paul
You can create custom middleware, you dont 'NEED' websockets per se`
This is my current application:
configureStore.js:
import * as SignalR from '#aspnet/signalr';
//to server
export default function configureStore(history, initialState) {
const middleware = [
thunk,
routerMiddleware(history),
SignalrInvokeMiddleware
];
const rootReducer = combineReducers({
...reducers,
router: connectRouter(history)
});
const enhancers = [];
const windowIfDefined = typeof window === 'undefined' ? null : window;
if (windowIfDefined && windowIfDefined.__REDUX_DEVTOOLS_EXTENSION__) {
enhancers.push(windowIfDefined.__REDUX_DEVTOOLS_EXTENSION__());
}
return createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middleware), ...enhancers)
);
}
const connection = new SignalR.HubConnectionBuilder()
.withUrl("/notificationHub")
.configureLogging(SignalR.LogLevel.Information)
.build();
//from server
export function SignalrInvokeMiddleware(store, callback) {
return (next) => (action) => {
switch (action.type) {
case "SIGNALR_GET_CONNECTIONID":
const user = JSON.parse(localStorage.getItem('user'));
connection.invoke('getConnectionId', user.userid)
.then(conid => action.callback());
break;
case "SIGNALR_USER_JOIN_REQUEST":
let args = action.joinRequest;
connection.invoke('userJoinRequest', args.clubId, args.userId);
break;
default:
}
return next(action);
}}
export function signalrRegisterCommands(store, callback) {
connection.on('NotifyUserJoinRequest', data => {
store.dispatch({ type: 'SIGNALR_NOTIFY_USERJOIN_REQUEST', notification: data });
})
connection.start()
.then(() => {
callback();
})
.catch(err => console.error('SignalR Connection Error: ', err));
}
index.jsx:
const store = configureStore(history);
const callback = () => {
console.log('SignalR user added to group');
}
signalrRegisterCommands(store, () => {
console.log('SignalR Connected');
store.dispatch({ type: 'SIGNALR_GET_CONNECTIONID', callback });
});
I'm new in graphql and I am trying to integrate an authentication/authorization system in my project. I found an example on Medium, but I do not understand how a guard communicates with a resolver. If someone knows, I will be very grateful.
import { ApolloServer } from 'apollo-server';
import gql from 'graphql-tag';
import { tradeTokenForUser } from './auth-helpers';
const HEADER_NAME = 'authorization';
const typeDefs = gql`
type Query {
me: User
serverTime: String
}
type User {
id: ID!
username: String!
}
`;
const resolvers = {
Query: {
me: authenticated((root, args, context) => context.currentUser),
serverTime: () => new Date(),
},
User: {
id: user => user._id,
username: user => user.username,
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => {
let authToken = null;
let currentUser = null;
try {
authToken = req.headers[HEADER_NAME];
if (authToken) {
currentUser = await tradeTokenForUser(authToken);
}
} catch (e) {
console.warn(`Unable to authenticate using auth token: ${authToken}`);
}
return {
authToken,
currentUser,
};
},
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
export const authenticated = next => (root, args, context, info) => {
if (!context.currentUser) {
throw new Error(`Unauthenticated!`);
}
return next(root, args, context, info);
};
I do not understand what "next" parameter does and why as an argument when this guard is called I have to return a value?
authenticated is higher-order function that makes the code DRY. next is a callback that is used as a predicate.
It's a DRYer way to write:
...
me: (root, args, context) => {
if (!context.currentUser) {
throw new Error(`Unauthenticated!`);
}
return context.currentUser;
)
...