How to test an Error of a Method in a Vue.js Component using jest - vue.js

How can I test the method createUser() of my Vue component? I want to test if the createUser() method throws an Error if the firstname < 2 for example. How is this possible?
I'm not really familiar with testing VUE components. It's my first time, so I have no idea how to get access the VUE component and how to submit for a example a username to the component
<script>
import {ApiService} from '../ApiService.js';
import {User} from '../User.js';
//const API_URL = 'http://localhost:8080';
const apiService = new ApiService();
export default {
name: "CreateUser",
data() {
return {
input: {
username: "",
firstname: "",
lastname: "",
title: "",
password: "",
groupId: "",
groups: [],
},
}
},
/.../
methods: {
getAllGroups() {
apiService.getAllGroups().then((data) => {
this.input.groups = data;
});
},
createUser() {
if (this.input.firstname == null || this.input.firstname.length < 2 || this.input.firstname > 50) {
throw ("Firstname to short/long/empty");
} else {
let user = new User(this.input.username, this.input.lastname, this.input.title, this.input.firstname, this.input.password, this.input.groupId)
apiService.createUser(user).then(() => {
location.reload()
});
}
},
I tried the following, but something doesn't not work
import { shallowMount } from '#vue/test-utils';
import UserModal from "../src/views/UserModal";
describe('UsarModal', () => {
it('should throw error when first name is too short', () => {
const myItems = [
{
username: "Heinz",
firstname: "H",
lasname: "Müller"}
]
const wrapper = shallowMount(UserModal, {
input: {
myItems
}
})
expect(wrapper.vm.createUser()).toThrow("Firstname to short/long/empty")
})
})

since in the code, it is throwing an error, so we will need to add a catch block in our test case to test this scenario. PFB example for your case:
try {
wrapper.vm.createUser();
} catch (error) {
expect(error).toBe('Firstname to short/long/empty');
}
let me know if you face any issue.

What you did in your example is very close. You just need to wrap the function call that is going to throw the exception in a lambda, e.g.
expect(() => wrapper.vm.createUser()).toThrow("Firstname to short/long/empty")
As described in the docs: https://jestjs.io/docs/expect#tothrowerror
It's probably doing something like internally wrapping the lambda in a try/catch, but I think using this method is a bit nicer than wrapping in a try/catch in your own test.

Thanks for the tip! But still something is not working right. It seems for me, that it does not accept my mock-data for input. I want to test if a got an error when I use a username which is too short. But even when I put a username that's long enough, the try catch block catches my error as you can see in the attached picture.
import {shallowMount} from '#vue/test-utils'
import UserModal from "./UserModal";
describe('ParentComponent', () => {
test("displays 'Emitted!' when custom event is emitted", () => {
const wrapper = shallowMount(UserModal, {
input: {
username: "asfsf",
firstname: "thomas",
lastname: "bird",
title: "Dr.",
password: "asdasda",
groupId: "2",
groups: [],}
});
try {
wrapper.vm.createUser();
} catch (error) {
expect(error).toBe("username missing");
}
})
});
Error Log

Related

How to use Nuxt Context to call Axios request with param

so I'm trying to get my Axios to do a get request with a param that'll end the url in
'/?user= {id}'
the id is passed in by my loggedInUser.id from Vuex. I know that async functions won't accept 'this' inside the call so I included store as a parameter. Something's still off with how I passed the data around thought I think. Would appreciate any help, thanks!
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters(["loggedInUser"])
},
head() {
return {
title: "Actors list"
};
},
components: {
EditProfile
},
async asyncData({ store }) {
try {
const body = { data: store.getters.loggedInUser.id };
const { actors } = await $axios.$get(`/api/v1/actors/`, {
params: {
user: body
}
});
return { actors };
} catch (e) {
return { actors: [] };
}
},
data() {
return {
actors: []
};
Edit
I got it to work when I removed the data: from 'const body' and removed the brackets as well around 'actor'
try {
const body = store.getters.loggedInUser.id;
const actors = await $axios.$get(`/api/v1/actors/`, {
params: {
user: body
}
});
You can access your params from Context.
Context is available in special nuxt lifecycle areas like asyncData, fetch, plugins, middleware and nuxtServerInit.
In Nuxt, with asyncData hook you can get query parameters from the route context key.
Please read the Nuxt.js Context documentation. The context provides additional objects/params from Nuxt to Vue components
With your-domain/?user=wonderman
asyncData({ route: { query: queryParams} }) {},
variable queryParams is an object:
{ user: "wonderman" }

Error: [vuex] Do not mutate vuex store state outside mutation handlers with Firebase Auth Object

I have been trying to solve this problem for a few hours now to no avail. Could someone help me spot the problem?
The error I am getting is:
Error: [vuex] Do not mutate vuex store state outside mutation handlers
Here is my login script section with the offending function in login()
<script>
import { auth, firestoreDB } from "#/firebase/init.js";
export default {
name: "login",
props: {
source: String
},
////////
layout: "login",
data() {
return {
show1: false,
password: "",
rules: {
required: value => !!value || "Required.",
min: v => v.length >= 8 || "Min 8 characters",
emailMatch: () => "The email and password you entered don't match"
},
email: null,
feedback: null
};
},
methods: {
login() {
if (this.email && this.password) {
auth
.signInWithEmailAndPassword(this.email, this.password)
.then(cred => {
//this.$router.push("/");
this.$store.dispatch("user/login", cred);
console.log()
this.$router.push("/forms")
console.log("DONE")
})
.catch(err => {
this.feedback = err.message;
});
} else {
this.feedback = "Please fill in both fields";
}
},
signup() {
this.$router.push("signup");
}
}
};
</script>
import { auth, firestoreDB } from "#/firebase/init.js";
export const state = () => ({
profile: null,
credentials: null,
userID: null
})
export const getters = {
getinfo:(state) =>{
return state.credentials
},
isAuthenticated:(state)=>{
if (state.credentials != null) {
return true
} else {
return false
}
}
}
export const mutations = {
commitCredentials(state, credentials) {
state.credentials = credentials
},
commitProfile(state, profile) {
state.profile = profile
},
logout(state){
state.credentials = null,
state.profile = null
}
}
export const actions = {
login({commit},credentials) {
return firestoreDB.collection("Users").where('email', '==', auth.currentUser.email).get()
.then(snapshot => {
snapshot.forEach(doc => {
let profile = {...doc.data()}
commit("commitCredentials", credentials)
commit("commitProfile", profile)
})
}).catch((e) => {
console.log(e)
})
},
credentials({ commit }, credentials) {
commit("commitCredentials",credentials)
},
logout() {
commit("logout")
},
}
I have checked that there is no where else that is directly calling the store state.
I have worked out that if I don't do the commitCredentials mutation which mutates credentials, the problem doesn't happen.
Another note to add, the error keeps printing to console as if it were on a for loop. So my console is flooded with this same message.
I am pretty sure this is to do with the firebase auth sign in and how the Credential object is being changed by it without me knowing, but I can't seem to narrow it down.
Any help would be very much welcomed.
Found the answer.
https://firebase.nuxtjs.org/guide/options/#auth
signInWithEmailAndPassword(this.email, this.password)
.then(cred)
"Do not save authUser directly to the store, since this will save an object reference to the state which gets directly updated by Firebase Auth periodically and therefore throws a vuex error if strict != false."
Credential object is constantly being changed by the firebase library and passing the credential object is just passing a reference not the actual values itself.
The solution is to just save the values within the object.

Vue Apollo: How can I query GraphQL using an object as Input argument?

I would like to create a checkout object via the GraphQL API provided by the Saleor eCommerce platform.
According to the gql playground there is a mutation to do so that takes a CheckoutCreateInput object as it's argument.
Here is an example mutation that works fine within the playground.
Here is the current code that I have tried (I am doing this within a vuex action)
export const actions = {
addToCart({ commit, dispatch }, cartItem) {
const currentCartItems = this.state.cartItems
// Check to see if we already have a checkout object
if (this.state.checkoutId !== '') {
// Create a new checkout ID
console.log('creating new checkout object')
try {
this.app.apolloProvider.defaultClient
.mutate({
mutation: CREATE_CART_MUTATION,
variables: {
checkoutInput: {
lines: { quantity: 10, variantId: 'UHJvZHVjdFZhcmlhbnQ6NQ==' },
email: 'test#test.com'
}
}
})
.then(({ data }) => {
console.log(data)
})
} catch (e) {
console.log(e)
}
} else {
console.log('checkout id already set')
}
// TODO: Check to see if the cart already contains the current Cart Item
commit('ADD_CART_ITEM', cartItem)
}
and here is the CREATE_CART_MUTATION:
import gql from 'graphql-tag'
export const CREATE_CART_MUTATION = gql`
mutation($checkoutInput: CheckoutCreateInput!) {
checkoutCreate(input: $checkoutInput) {
checkout {
id
created
lastChange
lines {
id
variant {
id
name
}
quantity
totalPrice {
gross {
localized
}
net {
localized
}
}
}
totalPrice {
gross {
localized
}
net {
localized
}
}
}
}
}
`
On the server this comes back with the following error:
graphql.error.base.GraphQLError: Variable "$checkoutInput" got invalid value {"email": "test#test.com", "lines": {"quantity": 10, "variantId": "UHJvZHVjdFZhcmlhbnQ6NQ=="}}.
In field "lines": In element #0: Expected "CheckoutLineInput", found not an object.
Looks like I was most of the way there, I was just passing a single lines object rather than an array of them. The correct code is as follows:
try {
this.app.apolloProvider.defaultClient
.mutate({
mutation: CREATE_CART_MUTATION,
variables: {
checkoutInput: {
lines: [
{ quantity: cartItem.quantity, variantId: cartItem.variantId }
],
email: 'test#test.com'
}
}
})
.then(({ data }) => {
console.log('mutation done!')
commit('SET_CHECKOUT_OBJECT', data.checkoutCreate.checkout)
})
} catch (e) {
console.log('error:')
console.log(e)
}

How can I pass the value from my API to my head tittle with vue-head?

I am using vue-head in website because of I have to pass the name of the program to the html head, and the inf. it is coming from an API, so I make the request but every time I try to pass the name it send me error this the code:
export default {
data: () => ({
errors: [],
programs: [],
firstVideo: {},
vidProgram: {}
}),
},
created() {
//do something after creating vue instance
this.api = new ApiCanal({})
this.getProgram()
},
methods: {
getProgram() {
this.api.http.get(`videos/program/${this.programSlug}`)
.then(response => {
this.programs = response.data
this.firstVideo = response.data[0]
this.vidProgram = response.data[0]['program']
})
.catch(error => {
this.errors = error
});
}
},
head: {
//this is the inf. for the head
title: {
inner: this.programs.name,
separator: '-',
complement: this.programs.info
}
}
}
I will really appreciate if you can help me with this issue
If you want to use properties of your Vue object/component in the title there, you need to make it a function, as currently this refers to the object creating your Vue component (probably the global window object).
head: {
title: function() {
return {
inner: this.programs.name,
separator: '-',
complement: this.programs.info
};
}
}

Realm "observer.next create #[native code]" exception

I am trying to fetch data with apollo and then write it to realm. I have created a js file that I know works, because it has worked before. But, when I try to write to a particular model I get an error message. More details as follows:
Code (Not entire code) LocationQuery.js:
const realm = new Realm({ schema: [testBuilding1], schemaVersion: 1 });
let buildingTypeArray = [];
const temp = [];
class LocationQuery extends Component {
static get propTypes() {
return {
data: React.PropTypes.shape({
loading: React.PropTypes.bool,
error: React.PropTypes.object,
sites: React.PropTypes.array,
}).isRequired,
};
}
render() {
if (this.props.data.loading) {
return (null);
}
if (this.props.data.error) {
return (<Text>An unexpected error occurred</Text>);
}
if (this.props.data.sites) {
this.props.data.sites.map((value) => {
buildingTypeArray.push(value.locations);
});
buildingTypeArray.forEach((locationValues) => {
realm.write(() => {
realm.create('testBuilding1', {
building: '273',
});
});
});
}
return null;
}
}
const locationQueryCall = gql`
query locationQueryCall($id: String!){
sites(id: $id){
locations {
building
type
}
}
}`;
const ViewWithData = graphql(locationQueryCall, {
options: props => ({
variables: {
id: 'SCH1',
},
}),
})(LocationQuery);
export default connect(mapStateToProp)(ViewWithData);
The error I get is a big red screen that read:
console.error: "Error in observe.next.... blah blah blah"
The Model I am using:
export const testBuilding1 = {
name: 'testBuilding1',
properties: {
building: 'string',
},
};
The weird thing is that the code works when I use this model:
export const locationScene = {
name: 'locationScene',
properties: {
building: 'string',
},
};
I am calling LocationQuery.js in another piece of code passing it through at render.
Thank you in advance for the help!