How can I test Vue 3 component with Pinia and axios token - axios

I have a component which calls a store called users:
Store:
import { defineStore } from 'pinia'
import axios from 'axios'
export const useUserApiStore = defineStore('userApiStore', {
state: () => ({
}),
actions: {
list(filter) {
const url = import.meta.env.VITE_URL_GLOBALTANK_BASE_API + import.meta.env.VITE_EP_USERS_LIST;
return new Promise((resolve, reject) => {
axios.get(url, {
params: {
filter: filter,
},
}).then(res => {
resolve(res)
}).catch(error => {
reject(error)
})
})
},
listPaginated(params) {
const url = import.meta.env.VITE_URL_GLOBALTANK_BASE_API + import.meta.env.VITE_EP_USERS_LIST_PAGINATE;
return new Promise((resolve, reject) => {
axios.get(url, {
params: params,
}).then(res => {
resolve(res)
}).catch(error => {
reject(error)
})
})
},
get(id) {
const url = import.meta.env.VITE_URL_GLOBALTANK_BASE_API + import.meta.env.VITE_EP_USERS_SHOW;
return new Promise((resolve, reject) => {
axios.get(url.replace(":id", id)).then(res => {
resolve(res)
}).catch(error => {
reject(error)
})
})
},
delete(id) {
const url = import.meta.env.VITE_URL_GLOBALTANK_BASE_API + import.meta.env.VITE_EP_USERS_DELETE;
return new Promise((resolve, reject) => {
axios.delete(url, { params: { id: id } }).then(res => {
resolve(res)
}).catch(error => {
reject(error)
})
})
},
/* TABS */
store(params) {
const url = import.meta.env.VITE_URL_GLOBALTANK_BASE_API + import.meta.env.VITE_EP_USERS_STORE;
return new Promise((resolve, reject) => {
axios.post(url, params).then(res => {
resolve(res)
}).catch(error => {
reject(error)
})
})
},
update(params) {
const url = import.meta.env.VITE_URL_GLOBALTANK_BASE_API + import.meta.env.VITE_EP_USERS_UPDATE;
return new Promise((resolve, reject) => {
axios.put(url, params).then(res => {
resolve(res)
}).catch(error => {
reject(error)
})
})
}
}
})
My component UsersView has the method onMounted that calls getData from store:
onMounted(() => {
getData();
});
const getData = (numPage = 0) => {
let params = {
paginate: model.paginate,
filter: model.filter,
page: model.current_page,
};
if (numPage > 0) {
params.page = numPage;
model.current_page = numPage;
}
userApiStore
.listPaginated(params)
.then((res) => {
model.data = res.data.data;
console.log("data", model.data);
})
.catch((err) => {
if (err.response.status === 401) console.log("UNAUTHORIZED");
notificationsStore.showToast(t("notifications.unknown_error"), "error");
});
};
And my UsersVew test:
it("should render users list", async () => {
const wrapper = mount(UsersView, {
global: {
plugins: [createTestingPinia({ createSpy: vi.fn, stubActions: false })]
}
})
await flushPromises()
const usersList = wrapper.findAllComponents('[data-test="users-list"]')
console.log(usersList)
})
The problem is that I have a previous login where I get the access_token and I put it globally in axios headers like this:
axios.defaults.headers.common['Authorization'] = Bearer ${res.data.access_token};
But I want to test my component but my component doesn't has the token globally when I throw the tests the list of users is empty
If anyone can help me I would be very grateful

Related

How to create new item in collection if not exists, otherwise, update price and quantity when added to cart

Hi iam new to Vue and trying too build a MEVN application. What iam trying to do is when user adds item in cart it should store one document in mongoDB and if user adds more of same item only the price and quantity for the document should increase and not create new document.
Here is code for client when user adds item in cart,iam using Vue3:
async addToCart(state, product) {
console.log(state);
let dbProducts = await axios
.get(`http://localhost:1337/items/`)
.then((res) => res.data)
.catch((error) => console.log(error));
let item = dbProducts.find((i) => i.id === product.id);
console.log(item);
console.log('addTOcart');
if (item) {
console.log('put request');
item.quantity++;
console.log('quantity', item.quantity);
axios
//.put(`http://localhost:1337/items/${uniqueId}`, item)
.put(`http://localhost:1337/items/`, item)
.then((res) => {
console.log(res.data);
alert(res.data);
})
.catch((error) => console.log(error));
} else {
product = { ...product, quantity: 1 };
state.cart.push(product);
axios.post('http://localhost:1337/items', {
id: product.id,
title: product.title,
price: product.price,
quantity: product.quantity,
shortDesc: product.shortDesc,
category: product.category,
longDesc: product.longDesc,
imgFile: product.imgFile,
serial: product.serial,
});
}
},
And here is code for the server, iam using express js:
const express = require('express');
const app = express();
const Items = require('./Items');
const connection = require('./connection');
const Port = process.env.Port || 1337;
const cors = require('cors');
app.use(cors());
connection();
app.use(express.json());
app.post('/items', (req, res) => {
const data = new Items(req.body);
data
.save()
.then((Items) => {
console.log('item saved', Items);
res.json({ succcess: true, Items });
})
.catch((err) => {
console.log(err);
});
});
app.get('/items', async (req, res) => {
Items.find({}, (err, items) => {
res.json(items);
});
});
app.put('/items', function (req, res) {
console.log(req.body);
//Items.updateOne({ _id: req.body._id }, req.body);
Items.findOneAndUpdate({ _id: req.body._id }, req.body);
// Items.findOne({ _id: req.body._id });
});
app.listen(Port, () => {
console.log(`App running on port ${Port}`);
});
As #HeikoTheißen suggested, you should handle the logic of the operation on the server, using a single POST request:
const express = require('express');
const app = express();
const Items = require('./Items');
const connection = require('./connection');
const Port = process.env.Port || 1337;
const cors = require('cors');
app.use(cors());
connection();
app.use(express.json());
app.post('/items', async (req, res) => {
try {
let item = await Items.findById(req.body.id);
if (!item) {
item = await Items.create(req.body);
} else {
item.quantity++;
await item.save();
}
res.json({ succcess: true, item });
} catch (err) {
res.json({ succcess: false });
}
});
app.listen(Port, () => {
console.log(`App running on port ${Port}`);
});
You should simplify your client code as:
async function addToCart(state, product) {
try {
const { data } = await axios.post('http://localhost:1337/items', product);
// Add new product to card if necessary
if (!state.cart.some((p) => p.id === data.item.id)) {
state.cart.push(data.item);
}
} catch (err) {
console.log(err);
}
}

React-Query: useInfiniteQuery

So, I have looked through the docs and answers on here and I'm still needing some help:
index.tsx
const getInfiniteArticles = ({ pageParams = 0 }) => {
const res = await axios.get('/api/articles', { params: { page: pageParams } });
return res.data;
}
api/articles.ts
const getArticles = async (req: NextApiRequest, res: NextApiResponse) => {
try {
const { page } = req.query;
const pageNum = Number(page);
const data = await NewsService.getArticles(getRange(pageNum));
return res.status(200).json({
data,
previousPage: pageNum > 0 ? (pageNum - 1) : null,
nextPage: pageNum + 1,
});
} catch (err) {
res.json(err);
res.status(405).end();
}
};
export default getArticles;
index.tsx
const { data: articlePages, fetchNextPage } = useInfiniteQuery(
'infinite-articles',
getInfiniteArticles,
{
getNextPageParam: (lastPage, allGroups) => {
console.log('lastPage: ', lastPage);
console.log('allGroups: ', allGroups);
return lastPage.nextPage;
}
});
const handleLoadMore = () => {
fetchNextPage();
};
console after clicking next page:
lastPage: { data: Array(50), previousPage: null, nextPage: 1}
allGroups: [
{ data: Array(50), previousPage: null, nextPage: 1},
{ data: Array(50), previousPage: null, nextPage: 1},
]
Any help on why I'm getting the same groups is appreciated! :)
So, it turns out my structure wasn't correct
const {
fetchNextPage,
fetchPreviousPage,
hasNextPage,
hasPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
...result
} = useInfiniteQuery(queryKey, ({ pageParam = 1 }) => fetchPage(pageParam), {
...options,
getNextPageParam: (lastPage, allPages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, allPages) => firstPage.prevCursor,
})
queryFn: (context: QueryFunctionContext) => Promise<TData>
The queryFn is supposed to be a synchronous function that returns a Promise
I was either passing an async function or I was returning the TData not a promise.
updated and working:
const getInfiniteArticles = ({ pageParam = 0 }) => axios.get('/api/articles', { params: { page: pageParam } });
const { data: articlePages, fetchNextPage } = useInfiniteQuery('articles', getInfiniteArticles, {
getNextPageParam: (lastPage, pages) => {
// the returned axios response
return lastPage.data.nextPage;
}
});
Reference Page

Cloud Firestore function triggers and transactions - how to return a promise correctly

I have a Cloud Firestore function trigger "onCreate". Depending on the value of a given field, I would like it to either update some documents via a transaction and to copy the created document as a record in Algolia, or to execute a completely different transaction. There are therefore several conditions and I am not sure that I am returning promises correctly, as sometimes the function is not copying the record in Algolia when expected.
I paste a simplified version of the code in case someone can help.
exports.createArticle = functions.firestore.document('articles/{articleId}').onCreate(async (snap, context) => {
const newDocData = snap.data()
if(newDocData) {
const userCreatorId = newDocData.createdBy
const userDocRef = imported.db.collection('users').doc(userCreatorId)
if(newDocData.type === 1) {
newDocData.objectID = newDocData.id
indexAlgolia.saveObject(newDocData)
.then(() => {
console.log('Article saved in Algolia with id:', newDocData.objectID )
})
.catch(err => {
console.log('ERROR while ADDING object inAlgolia:', err)
})
return imported.db.runTransaction(async t => {
// do some work
const userDoc = await t.get(userDocRef)
const userData = userDoc.data()
if (userData && userData.field1 > 0) {
t.update(userDocRef, {field2: true})
}
}).then(result => {
console.log('Transaction success')
}).catch(err => {
console.log('Transaction failure:', err)
})
}
else {
const colOneRef = imported.db.collection('colOne')
colOneRef.where('field2', '==', newDocData.field3).limit(1).get().then(snapshot => {
return imported.db.runTransaction(async t => {
if (snapshot.empty) {
t.update(userDocRef, {field3: false})
}
const decrement = imported.fieldValue.increment(-1)
t.update(userDocRef, {field4: decrement})
}).then(result => {
console.log('Transaction success')
}).catch(err => {
console.log('Transaction failure:', err)
})
}).catch(() => 'Error while querying colOneRef')
}
}
})
When you have multiple async/then calls you canmake them await the result and run them as if they are synchornous but from your code I see that the second doesn't depent on the first one so you can put them in a Promse.all() to make the function finish faster because they will run in parallel. Your code would look like this:
xports.createArticle = functions.firestore
.document("articles/{articleId}")
.onCreate(async (snap, context) => {
const newDocData = snap.data();
if (newDocData) {
const userCreatorId = newDocData.createdBy;
const userDocRef = imported.db.collection("users").doc(userCreatorId);
if (newDocData.type === 1) {
newDocData.objectID = newDocData.id;
const firstPromise = indexAlgolia
.saveObject(newDocData)
.then(() => {
console.log(
"Article saved in Algolia with id:",
newDocData.objectID
);
})
.catch((err) => {
console.log("ERROR while ADDING object inAlgolia:", err);
});
const secondPromise = imported.db
.runTransaction(async (t) => {
// do some work
const userDoc = await t.get(userDocRef);
const userData = userDoc.data();
if (userData && userData.field1 > 0) {
t.update(userDocRef, { field2: true });
}
})
.then((result) => {
console.log("Transaction success");
})
.catch((err) => {
console.log("Transaction failure:", err);
});
return Promise.all([firstPromise, secondPromise]);
} else {
const colOneRef = imported.db.collection("colOne");
return colOneRef
.where("field2", "==", newDocData.field3)
.limit(1)
.get()
.then((snapshot) => {
return imported.db
.runTransaction(async (t) => {
if (snapshot.empty) {
t.update(userDocRef, { field3: false });
}
const decrement = imported.fieldValue.increment(-1);
t.update(userDocRef, { field4: decrement });
})
.then((result) => {
console.log("Transaction success");
})
.catch((err) => {
console.log("Transaction failure:", err);
});
})
.catch(() => "Error while querying colOneRef");
}
return
}
});

Realtime Gifted Chat with Socket.io issues

I'm trying to get Gifted Chat implemented in a realtime fashion with socket.io but I'm having issues. I'm able to get socket.io to connect, the message to be emitted, but it isn't showing up in real time when I have an android emulator and an iPhone simulator both running the app.
server.js
const express = require("express");
const http = require("http");
const app = express();
const server = http.createServer(app);
// Attempt at Socket.io implementation
const socket = require('socket.io')
const io = socket(server)
const bodyParser = require('body-parser');
const Message = require("./models/message");
const SportsMessage = require('./models/sportsMessage')
const GamerMessage = require('./models/gamerMessage')
const mongoose = require('mongoose');
// MongoDB connection
mongoose.connect(
'mongodb+srv://yada:yada#cluster0.kt5oq.mongodb.net/Chatty?retryWrites=true&w=majority', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('Connected to the database!')
}).catch(() => {
console.log('Connection failed oh noooooo!')
});
// Parse the request body as JSON
app.use(bodyParser.json());
// GET messages, don't change these bro
app.get("/api/messages", (req, res) => {
Message.find({}).exec((err, messages) => {
if(err) {
res.send(err).status(500);
} else {
res.send(messages).status(200);
}
});
});
app.get("/api/sportsMessages", (req, res) => {
SportsMessage.find({}).exec((err, messages) => {
if(err) {
res.send(err).status(500);
} else {
res.send(messages).status(200);
}
});
});
app.get("/api/gamerMessages", (req, res) => {
GamerMessage.find({}).exec((err, messages) => {
if(err) {
res.send(err).status(500);
} else {
res.send(messages).status(200);
}
});
});
// POST messages
app.post('/api/messages', (req, res) => {
Message.create(req.body).then((message) => {
res.send(message).status(200);
}).catch((err) => {
console.log(err);
res.send(err).status(500);
});
});
app.post('/api/sportsMessages', (req, res) => {
SportsMessage.create(req.body).then((message) => {
res.send(message).status(200);
}).catch((err) => {
console.log(err);
res.send(err).status(500);
});
});
app.post('/api/gamerMessages', (req, res) => {
GamerMessage.create(req.body).then((message) => {
res.send(message).status(200);
}).catch((err) => {
console.log(err);
res.send(err).status(500);
});
});
// Socket.io connection
io.on('connection', socket => {
socket.emit('your id', socket.id)
socket.on('send message', body => {
console.log(body)
io.emit('send message', body)
})
console.log("connected to dat socket boiii")
})
server.listen(8000, () => console.log("server is running on port 8000"));
Chat Screen
import React, { useState, useEffect, useContext, useRef } from 'react'
import { View, Text, Button, StyleSheet } from 'react-native'
import io from 'socket.io-client'
import useMessages from '../hooks/useMessages'
import { Context as UserContext } from '../context/UserContext'
import { GiftedChat as GChat } from 'react-native-gifted-chat'
const GeneralChat = () => {
const [messages, ids, getMessages, randomId, setMessages] = useMessages()
const { state: { username } } = useContext(UserContext)
const socketRef = useRef()
socketRef.current = io('{MyIP}')
useEffect(() => {
getMessages()
randomId()
const socket = io('{MyIP}')
socket.on('your id', id => {
console.log(id)
})
}, [])
const onSend = (message) => {
let userObject = message[0].user
let txt = message[0].text
console.log(message)
setMessages(previousMessages => GChat.append(previousMessages, message))
const messageObject = {
text: txt,
user: userObject
}
socketRef.current.emit('send message', messageObject)
fetch("{MyIP}/api/messages", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(messageObject)
}).then((res) => {
return res.json();
}).catch((err) => {
console.log(err);
});
}
return (
<GChat
// isLoadingEarlier
scrollToBottom
infiniteScroll
loadEarlier
alwaysShowSend
renderUsernameOnMessage
inverted={true}
showUserAvatar
messages={messages}
onSend={message => onSend(message)}
user={{
_id: ids,
name: username,
avatar: 'https://placeimg.com/140/140/any'
}}
/>
)
}
GeneralChat.navigationOptions = () => {
return {
title: 'General Chat',
}
}
const styles = StyleSheet.create({
})
export default GeneralChat

Mongoose: findByIdAndUpdate is not working even after passing {new:true}

POST and DELETE requests are working but PUT is not working even after passing {new: true} as other answers suggested.
I checked the documentation for mongoose and didn't find anything that might solve the problem.
Terminal log is: PUT /api/persons/5dfbb8677d7d960358dbdead 404 175 - 2.273 ms -
The request body is not logging and only a '-' is logged. This is not the case with POST.
Relevant code:
app.post('/api/persons', (request, response) => {
const body = request.body
const person = new Person({
name: body.name,
number: body.number,
})
person
.save()
.then(savedContact => {
response.json(savedContact.toJSON())
})
})
app.put('api/persons/:id', (request, response, next) => {
const body = request.body
const person = {
name: body.name,
number: body.number,
}
person
.findByIdAndUpdate(request.params.id, person, { new: true })
.then(updatedContact => {
response.json(updatedContact.toJSON())
})
.catch(error => next(error))
})
app.delete('/api/persons/:id', (request, response, next) => {
Person
.findByIdAndRemove(request.params.id)
.then(result => {
response.status(204).end()
})
.catch(error => {next(error)})
const errorHandler = (error, request, response, next) => {
if (error.name === 'CastError' && error.kind == 'ObjectId') {
return response.status(400).send({ error: 'malformatted id' })
}
next(error)
}
app.use(errorHandler)
})
Complete File:
require('dotenv').config()
const express = require('express')
const app = express()
app.use(express.static('build'))
const bodyParser = require('body-parser')
app.use(bodyParser.json())
const cors = require('cors')
app.use(cors())
const morgan = require('morgan')
morgan.token('req_body', function(req, res) {
if (req.method === 'POST' || req.method === 'PUT'){
return JSON.stringify(req.body);
}
});
morgan.token('req_key', function(req, res) {
if (req.method === 'GET' || req.method === 'PUT'){
return JSON.stringify(req.params.id);
}
});
app.use(morgan(':method :url :status :res[content-length] - :response-time ms :req_body :req_key'))
const Person = require('./models/person')
app.get('/api/persons', (request, response) => {
Person.find({}).then(persons => {
response.json(persons.map(person => person.toJSON()))
})
})
app.get('/api/persons/:id', (request, response) => {
Person
.findById(request.params.id)
.then(person => {
response.json(person.toJSON())
})
.catch(error => {
console.log(error)
response.status(404).end()
})
})
app.post('/api/persons', (request, response) => {
const body = request.body
const person = new Person({
name: body.name,
number: body.number,
})
person
.save()
.then(savedContact => {
response.json(savedContact.toJSON())
})
})
app.put('api/persons/:id', (request, response, next) => {
const body = request.body
const person = {
name: body.name,
number: body.number,
}
Person
.findByIdAndUpdate(request.params.id, person, { new: true })
.then(updatedContact => {
response.json(updatedContact.toJSON())
})
.catch(error => next(error))
})
app.delete('/api/persons/:id', (request, response, next) => {
Person
.findByIdAndRemove(request.params.id)
.then(result => {
response.status(204).end()
})
.catch(error => {next(error)})
})
const errorHandler = (error, request, response, next) => {
if (error.name === 'CastError' && error.kind == 'ObjectId') {
return response.status(400).send({ error: 'malformatted id' })
}
next(error)
}
app.use(errorHandler)
const PORT = process.env.PORT
app.listen(PORT, ()=>{console.log(`Server running on ${PORT}`)})
Your person object is wrong so not update record.
app.put('/api/persons/:id', (request, response, next) => {
const body = request.body
const person = {
name: body.name,
number: body.number,
}
Person
.findByIdAndUpdate(request.params.id, person, { new: true })
.then(updatedContact => {
response.json(updatedContact.toJSON())
})
.catch(error => next(error))
})