"Request failed with status code 404" error in jest test with Axios - vuejs2

I am running the following test in a Vue app:
import axios from 'axios';
import flushPromises from 'flush-promises';
import MockAdapter from 'axios-mock-adapter';
import TenantAlertService from '#/services/TenantAlertService';
import ServiceUrlProvider from '#/utils/ServiceUrlProvider';
import userAlerts from '#/store/modules/userAlerts';
import AlertToPlain from '#/transform/AlertToPlain';
import Alert from '#/models/Alert';
describe('TenantAlertService Service', () => {
let mock;
let data;
const tenantCode = 'RedAlert';
const id = 'zyx-abc';
const personId = '123456';
const appCode = 'asdfklj3';
const message = {
text: 'foo',
template: 'MY_TEMPLATE',
};
const person = {
id: personId,
};
const messageUrl = ServiceUrlProvider.gmiUrl()
.concat('/tenant/')
.concat(tenantCode)
.concat('/person/')
.concat(id)
.concat('/message');
const responseUrl = ServiceUrlProvider.gmiUrl()
.concat('/tenant/')
.concat(tenantCode)
.concat('/person/')
.concat(id)
.concat('/message/response');
const sendMessageUrl = ServiceUrlProvider.gmiUrl()
.concat('/tenant/')
.concat(tenantCode)
.concat('/app/')
.concat(appCode)
.concat('/template/')
.concat(message.template)
.concat('/person/')
.concat(person)
.concat('/message');
beforeEach(() => {
mock = new MockAdapter(axios);
data = { response: true };
});
it('fetchAll should be called', async () => {
const messageData = [
'ele1',
];
const responseData = [
'ele2',
];
mock.onGet(messageUrl).reply(200, messageData);
mock.onGet(responseUrl).reply(200, responseData);
const resp = await TenantAlertService.fetchAll({ tenantCode, id });
expect(resp.data).toEqual(['ele1', 'ele2']);
});
it('sendMessage should be called', async () => {
mock.onPost(sendMessageUrl).reply(200, data);
const resp = await TenantAlertService.sendMessage({
tenantCode,
appCode,
personId,
message,
});
expect(resp.status).toBe(200);
});
/* Store Actions */
it('store sendMessage', async () => {
const context = {
dispatch: jest.fn(),
getters: {
getComponent: 'Component 1',
},
};
mock.onPost(sendMessageUrl).reply(200, new Alert({}));
userAlerts.actions.sendMessage(context, {
tenantCode,
appCode,
person,
message,
});
await flushPromises();
expect(context.dispatch).toHaveBeenCalledWith('addOneSorted', new AlertToPlain(new Alert({})));
});
});
and getting the following results on the last two tests(sendMessage should be called and store sendMessage):
Request failed with status code 404
at createErrorResponse (node_modules/axios-mock-adapter/src/utils.js:117:15)
at Object.settle (node_modules/axios-mock-adapter/src/utils.js:97:16)
at handleRequest (node_modules/axios-mock-adapter/src/handle_request.js:78:11)
at node_modules/axios-mock-adapter/src/index.js:18:9
at MockAdapter.<anonymous> (node_modules/axios-mock-adapter/src/index.js:17:14)
at dispatchRequest (node_modules/axios/lib/core/dispatchRequest.js:59:10)
I am running the exact same configuration for mocking axios calls in 19 other tests that are passing, so I'm fairly certain the issue is not with my axios config (as seen here for example).
Is there something else I'm missing that could be causing this error?

Related

How to pass reactive data to Vue components using pinia store elements?

GamePage.vue
Destructured the pinia state elements and action method
const $store = useGameStore();
const {game, teamOne, teamTwo} = storeToRefs($store);
const { getGame } = $store;
Passed the destructed variables to components
<player-stat-table
:title="teamTwo.name"
:players="teamTwo.players"
:teamColor="teamTwo.team_color"
/>
Table Display
store/game_store.js
I am trying to edit data from the above table using updatePlayer action, after successfully completing the action I am updating the entire store data by recalling the get action method. But the data in the table is not updating reactively, it's updating after page reload. How to update it reactively?
import { api } from 'boot/axios'
import { defineStore } from 'pinia'
import { splitPlayers } from 'src/helpers'
export const useGameStore = defineStore('game', {
state: () => ({
game: null,
teamOne: null,
teamTwo: null,
}),
getters: {
getTeamOne: state => state.teamOne,
getTeamTwo: state => state.teamTwo,
getGameData: state => state.game,
},
actions: {
getGame(payload) {
return new Promise((resolve, reject) => {
api.get(`/games/${payload.gameID}/`)
.then(resp => {
const data = resp.data;
const teams = splitPlayers(data)
this.game = data
this.teamOne = teams[0]
this.teamTwo = teams[1]
resolve(data)
})
})
},
updatePlayer(payload) {
return new Promise((resolve, reject) => {
api.put(`/playerstat/${payload.id}/`, data)
.then(resp => {
const data = resp.data;
this.getGame({gameID: data.game})
resolve(data)
})
})
},
}
})
First, you can get rid of you getters, cause due to pinia documentation,
as getters you can think of as the computed properties
and you're not computing anything. So you can simply access the state properties, what you are already doing in your GamePage.vue file.
Secondly, you should also consider async/await pattern instead of Promiste.then(). Like mentioned in the comments, there's a problem with promise constructor antipattern in the OP.
I also prefer writing my pinia stores with the setup() approach, because I think it fits the vue3/composition-api approach a bit better.
import { api } from 'boot/axios'
import { defineStore } from 'pinia'
import { splitPlayers } from 'src/helpers'
export const useGameStore = defineStore('game', () => {
const game = ref(null);
const teamOne = ref(null);
const teamTwo = ref(null);
const getGame = async (gameId) => {
const resp = await api.get(`/games/${gameId}/`);
const teams = splitPlayers(resp.data)
game.value = resp.data
teamOne.value = teams[0]
teamTwo.value = teams[1]
};
const updatePlayer = async (data) => {
const resp = await api.put(`/playerstat/${data.id}/`, data)
const gameId = resp.data.game;
await getGame(gameId)
};
return {
game,
teamOne,
teamTwo,
getGame,
updatePlayer
}
});

React Native: How to add items to the set state of useState for getting socket notifications?

I need a function for getting notification from socket (TypeScript) .
For instance ,
when a user click the "Like",the receiver will receive a notice like "You have receive a like from XXX",and I am able to get this message from the below code ,however ,I am not sure how to save those notifications into a list in order to display all the notices ..Could you please take a look how to do it ? Thank you so much in advance !!
I have putted the socket in the useContext :
import React from 'react';
import socketio from 'socket.io-client';
export const socket = socketio.connect(SOCKET_URL);
export const SocketContext = React.createContext();
When I send click a like, the receiver can receive my notification, and then the remark in the below codes,I can't get the notification list :
import {SocketContext} from '../../auth/context';
import React, {useEffect, useState, useContext, useLayoutEffect} from 'react';
const Home = () =>{
const {socket, user} = useContext(SocketContext);
const [notificationCount, setNotificationCount] = useState([]);
const [me, setMe] = useState({});
// init data
const initialData = async () => {
try {
const meResult = await fetchGetMe();
setMe(meResult?.data.data);
} catch (error) {
console.log('initial data get errors:', error);
}
};
useLayoutEffect(() => {
initialData();
}, []);
//get feedback from socket
useEffect(() => {
socket.on('getNotification', data => {
setNotificationCount(pre=> [...pre, data]); //I got the problem here..Can't get the list
console.log('notification data :', notificationCount);
});
return () => {
socket.off('getNotification');
};
}, [socket]);
const onPressLike = ()=>{
socket.emit('sendNotification', {
senderUserId: me?.userId,
senderName: me?.userName,
receiverUserId: 123456,
type: 0, // 0:like 1.gifts 2.sunflower
});
}
<Button onClick={onPressLike}>Like</Button>
}
3.My socket config in the server part :
let onlineUsers = [];
const addUsers = (userId, socketId) => {
!onlineUsers.some((m) => m.userId !== userId) &&
onlineUsers.push({ userId, socketId });
};
const removeUser = (socketId) => {
onlineUsers = onlineUsers.filter((user) => user.socketId !== socketId);
};
const getUser = (receiverId) => {
return onlineUsers.find((m) => m.userId === receiverId);
};
io.on("connection", (socket) => {
console.log("connect now");
socket.on("newUser", (userId) => {
addUsers(userId, socket.id);
console.log("onlineUsers:", onlineUsers);
});
socket.on(
"sendNotification",
({ senderUserId, senderName, receiverUserId, type }) => {
console.log(
`senderName:${senderName},receiverID:${receiverUserId};type:${type},socketId:${socket.id};senderUserId:${senderUserId}`
);
console.log("sendNotification,onlineUsers:", onlineUsers);
let receiver = {};
if (onlineUsers.length > 0) {
receiver = getUser(senderUserId);
console.log("receiver:", receiver);
io.to(receiver.socketId).emit("getNotification", {
senderName,
type,
});
} else {
receiver = null;
console.log("receiver:", receiver);
socket.emit("getNotification", { receiver });
}
}
);
socket.on("disconnect", () => {
console.log("disconnect");
});
});

Testing custom hook - not wrapped in act warning

I' trying to test a custom hook but I receive this warning message
console.error node_modules/#testing-library/react-hooks/lib/core/console.js:19
Warning: An update to TestComponent inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser.
This is my custom hook
import { useState, useEffect } from 'react'
import io from 'socket.io-client'
import config from './../../../../config'
const useNotificationsSocket = (user) => {
const [socket, setSocket] = useState(null)
const [numUnreadMessages, setNumUnreadMessages] = useState(0)
const configureSocket = socket => {
socket.on('connect', () => {
const data = {
user: user,
}
socket.emit('user joined', data)
})
socket && socket.on('messages updated', (data) => {
//console.log(data)
setNumUnreadMessages(data.numUnreadMessages)
})
}
useEffect(() => {
const fetchSocket = async () => {
const s = await io(config.nSocket.url, {transports: ['websocket']})
configureSocket(s)
setSocket(s)
}
// Check that user is not an empty object as this causes a crash.
user && user.Id && fetchSocket()
}, [user])
return [socket, numUnreadMessages]
}
export { useNotificationsSocket }
and this is the test
import { renderHook, act } from '#testing-library/react-hooks'
import { useNotificationsSocket } from './../hooks/useNotificationsSocket'
jest.mock('socket.io-client')
describe('useNotificationsSocket', () => {
it('returns a socket and numUnreadMessages', async () => {
const user = { Id: '1' }
const { result } = renderHook(() => useNotificationsSocket(user))
expect(result).not.toBeNull()
})
})
I've tried importing act and wrapping the code in a call to act but however I try to wrap the code I still get a warning and can't figure out how I should use act in this case.
Your hook is asynchronous, so you need to await its response:
describe('useNotificationsSocket', () => {
it('returns a socket and numUnreadMessages', async () => {
const user = { Id: '1' }
const { result } = renderHook(() => useNotificationsSocket(user))
await waitFor(() => expect(result).not.toBeNull())
})
})
Additionally, if you define multiple tests, you may encounter your original error if you fail to unmount the hook. At least this appears to be the behaviour in #testing-library/react v13.3.0. You can solve this by unmounting the hook when your test completes:
describe('useNotificationsSocket', () => {
it('returns a socket and numUnreadMessages', async () => {
const user = { Id: '1' }
const { result, unmount } = renderHook(() => useNotificationsSocket(user))
await waitFor(() => expect(result).not.toBeNull())
unmount()
})
})

Vue and Gnosis Safe: Cannot read properties of undefined (reading 'addListeners')

I cought error, when I tried to add listeners. Can someone help me to solve this problem? I used Vue3 and Gnosis Safe.
mounted() {
const appsSdk = new initSdk();
const onSafeInfo = (safeInfo) => {
this.data.safeInfo = safeInfo;
appsSdk.initContracts();
};
const onTransactionConfirmation = ({ requestId, safeTxHash }) => {
console.log(requestId, safeTxHash);
};
const onTransactionRejection = ({ requestId }) => {
console.log(requestId);
};
appsSdk.addListeners({
onSafeInfo,
onTransactionConfirmation,
onTransactionRejection,
});
},

NuxtJS dispatch is not loading data

I've been struggling for 5 hours with the following issue.
I have a service file where I have API calls using Axios. In the store, I have an action that uses the service to pull a list of schools, then I commit the data to the mutations. If I console log the data on the mutation object, it works correctly and shows the data. However, when I call dispatch from the component inside the onMounted hook, I get an empty object. Any help is greatly appreciated. (see the code below)
store/schools.js
export const state = () => ({
mySchools: []
});
export const mutations = {
getSchools(state, data) {
state.schools = data;
console.log(state.schools); // works;
}
};
export const actions = {
async getMySchools({ commit }) {
await this.$getSchools().then(response => {
commit("getSchools", response.data);
});
}
};
portal/dashboard.vue
import {onMounted, ref, useStore} from "#nuxtjs/composition-api";
export default {
layout: 'portal',
setup() {
const store = useStore();
const schools = ref([]);
onMounted(async() => {
await store.dispatch('schools/getMySchools'); // is not pulling data
schools.value = store.state.schools.mySchools;
console.log(schools); // empty
});
return {
schools
}
}
};
Thank you
You shouldn't use await with then
try this
async getMySchools({ commit }) {
const response = await this.$getSchools();
commit("getSchools", response.data);
}
I'm assuming that your this.$getSchools() actually works since I'm not sure what that is and it's not part of the code