Mocking GraphQL API with MSW for Testing - testing

I'm trying to mock graphql API for testing react app but facing a problem
the handler is:
import { graphql } from 'msw'
export const postsGql = [
{
userId: 1,
id: 1,
title: 'first post title',
body: 'first post body',
},
{
userId: 2,
id: 5,
title: 'second post title',
body: 'second post body',
}
]
Define handlers that catch the corresponding requests and returns the mock data.
export const graphqlHandlers = [
graphql.query('posts', async(req, res, ctx) => {
return res(
ctx.data(
postsGql,
),
)
}),
]
my test file:
it('Should return posts when clicking fetch with graphql button', async() => {
render(<ApolloProvider client={client}>
<App />
</ApolloProvider>)
expect(screen.getByRole('heading', { name: 'MSW Testing Library Example', level: 1 })).toBeDefined()
userEvent.click(screen.getByRole('button', { name: 'Fetch Posts GraphQL' }))
await waitForElementToBeRemoved(() => screen.queryByLabelText('loading'))
postsGql.forEach((posts) => {
expect(screen.getByRole('heading', { name: posts.title, level: 2 })).toBeDefined()
expect(screen.getByText(posts.body)).toBeDefined()
})
})
but faced this error:
Missing field 'posts' while writing result [
{
"userId": 1,
"id": 1,
"title": "first post title",
"body": "first post body"
},
{
"userId": 2,
"id": 5,
"title": "second post title",
"body": "second post body"
}
]
I will appreciate any kind of help
thanks

Related

Why sequelize return result different than console.log(return)?

I try to send the data through postman and the data result is clean(without another property). But when I try to console.log(data), there are many other properties. I read on another thread(Sequelize return result is different than console.log(result)), this is because res.json serialized the data into a plain object with model props from dataValues. But how can res.json only get the dataValues property meanwhile the other properties are ignored?
my code:
async getItems(req, res, next){
const data = await Item.findAll({
attributes: ['id', 'name', 'price']
});
console.log(data);
return res.status(200).json(data);
};
postman result:
[
{
"id": 1,
"name": "PS5",
"price": 600
},
{
"id": 2,
"name": "XBOX X",
"price": 400
}
]
console.log(data) result:
[
Item {
dataValues: {
id: 1,
name: 'PS5',
price: 600
},
_previousDataValues: {
id: 1,
name: 'PS5',
price: 600
},
uniqno: 1,
_changed: Set(0) {},
_options: {
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [Array]
},
isNewRecord: false
},
Item {
dataValues: {
id: 2,
name: 'XBOX X',
price: 400
},
_previousDataValues: {
id: 2,
name: 'XBOX X',
price: 400
},
uniqno: 1,
_changed: Set(0) {},
_options: {
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [Array]
},
isNewRecord: false
}
]
Sequelize models implement a toJSON method which JSON.stringify calls under the hood. You can also call model.toJSON() to get cleaner logs:
https://sequelize.org/docs/v6/core-concepts/model-instances/#note-logging-instances
Another example:
JSON.stringify({
toJSON() {
return 'arbitrary value';
}
});
// => "arbitrary value"

TypeError: $data.quotation.company is undefined

I have problem when I try to render data in my Vue3 application.
data() {
return {
quotation: [],
}
},
mounted() {
this.getQuotation()
},
methods: {
async getQuotation() {
this.$store.commit('setIsLoading', true)
const quotationID = this.$route.params.id
await axios
.get(`/api/v1/quotations/${quotationID}/`)
.then((response) => {
this.quotation = response.data
})
.catch(error => {
console.log(error)
})
},
}
The weird part is when I try to access {{quotation.company}} in template I can see the element of "company" without any error. The error TypeError: $data.quotation.company is undefined occurs when I get in depth {{quotation.company.name}} for example.
Axios is getting data like:
{
"id": 20,
"company": {
"id": 4,
"name": "xxxx",
"slug": "xxx",
"categories": [
{
"id": 7,
"name": "xxxx",
"slug": "xxxx"
}
],
"street2": "",
"postcode": 11111,
},
"home_type": "xxxx",
"Urgency": "",
"description": "xxxx",
}
I really don't understand :/
First the quotation property should be declared as an object like quotation: {}, then at the first rendering the field company is not available yet, so you need to add some conditional rendering as follows :
<div v-if="quotation.company" >
{{quotation.company.name}
</div>

How to use vue getters to find a value inside an object?

I want to get a specific value of an object inside the state of vuex.
Let me show you what I mean:
import { createStore } from "vuex";
export default createStore({
state: {
cards: [{
title: "Blog 1",
htmlCode: "This is blog 1",
index: 1,
},
{
title: "Blog 2",
htmlCode: "This is blog 2",
index: 2,
},
{
title: "Blog 3",
htmlCode: "This is blog 3",
index: 3,
},
{
title: "Blog 4",
htmlCode: "This is blog 4",
index: 4,
},
{
title: "Blog 5",
htmlCode: "This is blog 5",
index: 5,
},
{
title: "Blog 6",
htmlCode: "This is blog 6",
index: 6,
},
{
title: "Blog 7",
htmlCode: "This is blog 7",
index: 7,
},
],
},
getters: {
getTodoById: (state) => (id) => {
return state.cards.find(todo => todo.index === id)
}
},
mutations: {},
actions: {},
modules: {},
});
Now if I insert this value in my code: <p>{{ this.$store.getters.getTodoById(2) }}</p>, I get this as result: { "title": "Blog 2", "htmlCode": "This is blog 2", "index": 2 }
What I want, is the value of for examplehtmlCode and that result would be This is blog 2.
Hopefully someone understands what I mean.
For clarity: I want this result in the browser: This is blog 2
It is very important for my website that it is done with vuex getters.
This is a posible solution
getTodoById: (state) => (id) => {
const todo = state.cards.find(todo => todo.index === id)
return todo.htmlCode
}
Other solution is create a todo data in the componente and in the created() add your getter and asign to this data.
data() {
return {
todo: null,
};
},
created() {
this.todo = this.$store.getters.getTodoById(id) // for example extracted by the route
},
<p>{{ todo.htmlCode }}</p>
This should work.
<p>{{ this.$store.getters.getTodoById(2).htmlCode}}</p>

How to populate a v-select component with json data coming from axios.get

I am having a hard time trying to populate a v-select component with data from backend. The backend data is in json format.
The array 'items_category' is not storing the data. So I see "No data available" in my v-select. Can anyone help me. Thanks. This is my code:
<v-select v-model="category" :items="items_category" chips dense></v-select>
data () {
return {
category: '',
items_category: [],
categories: [],
i: 0
}
},
created () {
this.initialize()
},
methods: {
initialize () {
axios.get('http://localhost:4000/categories', {
})
.then(response => {
this.categories = response.data
for (this.i=0; this.i<this.categories.length; this.i++) {
this.items_category[this.i] = this.categories[this.i].category_name
}
})
.catch(function (error) {
console.log(error);
})
}
}
This is my json (http://localhost:4000/categories):
[
{
"id": 1,
"category_name": "Name 1",
"category_description": "Description 1"
},
{
"id": 2,
"category_name": "Premium",
"category_description": "Description 2"
},
{
"id": 3,
"category_name": "Free",
"category_description": "Description 3"
}
]
Ok I got it correct by using the push method
this.items_category.push(this.categories[this.i].category_name)

Shopping Cart with Vue and Vuex

I have cloned this awesome shopping cart repo from https://github.com/vueschool/learn-vuex, it works good but doesn't handle data for my use case. For anyone who has used this repo, how do i extend it by getting products from database or Api?
Shop.js
const _products = [
{"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2},
{"id": 2, "title": "H&M T-Shirt White", "price": 10.99,
"inventory": 10},
{"id": 3, "title": "Charli XCX - Sucker CD", "price": 19.99,
"inventory": 5}
]
export default {
getProducts (cb) {
setTimeout(() => cb(_products), 100)
},
buyProducts (products, cb, errorCb) {
setTimeout(() => {
// simulate random checkout failure.
(Math.random() > 0.5 ||
navigator.userAgent.indexOf('PhantomJS') > -1)
? cb()
: errorCb()
}, 100)
}
}
Shop gets called via vuex actions
actions: {
fetchProducts({commit}) {
return new Promise((resolve, reject) => {
// make the call
// call setProducts mutation
shop.getProducts(products => {
commit('setProducts', products)
resolve()
})
})
}
You can use axios to make a call to the server and get products like following
export default new Vuex.Store({
state: {
products: {},
},
actions: {
getProducts({commit},data) {
axios.get(`api/product?page=`+ data.page + '&orderBy='+ data.orderBy).then((response) => {
commit('updateProducts', response.data);
})
},
mutations: {
updateProducts (state, products) {
state.products = products
}
}
});