Best way to handle CRUD testing? - hapi.js

I want to write a test for my CRUD endpoints. But I want to test 'UPDATE', 'DELETE' endpoints rely on created document in 'CREATE' endpoint.
For example:
let createdAccount = null;
it("should create an account", async () => {
const response = await Server.inject({
method: "POST",
url: "/v1/accounts",
payload: JSON.stringify({
name: "TEST",
email: "test#test.com"
})
});
expect(response.statusCode).to.equal(200);
expect(response.result).to.a.object();
expect(response.result._id).to.exists();
createdAccount = response.result;
});
it("should delete an account", async () => {
const deleteResponse = await Server.inject({
method: "DELETE",
url: `/v1/accounts/${createdAccount._id}`
});
expect(deleteResponse.statusCode).to.equal(200);
expect(deleteResponse.result).to.a.object();
expect(deleteResponse.result._id).to.exists();
});
What's the best way to handle this? Should I create a test case which is rely on another one's result?
Note: I'm using hapijs, hapi/lab, hapi/code for testing.

Your use case is perfectly OK. We also use similar approaches in our test cases.
Here is a piece of test code from a real-world application.
describe('Validate campaign routes', () => {
let server, token, cookie, campaignId;
before(async () => {
server = await Glue.compose(serverConfig.manifest, options);
// custom my api related stuff, such as JTW token generation user creation etc.
});
after(async () => {
await mongoose.connection.db.dropDatabase();
await server.stop();
await helpers.delay(100);
});
it("should create a campaign", async () => {
const res = await server.inject({
url: '/campaign',
method: 'post',
payload: {
name: "Sample Campaign",
active: true
},
headers: {
"Authorization": token,
}
});
expect(res.statusCode).to.equal(200);
expect(res.result.created).to.exist();
expect(res.result.created.name).to.equal("Sample Campaign");
expect(res.result.status).to.equal(true);
campaignId = res.result.created.id;
});
it("should fetch all campaigns", async () => {
const res = await server.inject({
url: '/campaign?page=1',
method: 'get',
headers: {
"Authorization": token,
}
});
expect(res.statusCode).to.equal(200);
expect(res.result.status).to.equal(true);
expect(res.result.results).to.be.an.array();
expect(res.result.results).to.have.length(1);
expect(res.result.results[0].name).to.equal('Sample Campaign');
});
it("should fetch campaign details", async () => {
// fetch campaign details
const res2 = await server.inject({
url: `/campaign/${campaignId}`,
method: 'get',
headers: {
"Authorization": token,
}
});
expect(res2.statusCode).to.equal(200);
expect(res2.result).to.be.an.object();
expect(res2.result.name).to.equal('Sample Campaign');
});
it("should update campaign", async () => {
const res = await server.inject({
url: `/campaign/${campaignId}`,
method: 'put',
payload: {
name: "Updated Campaign Title",
maxImpression: 1000,
endDate: "01-04-2019"
},
headers: {
"Authorization": token,
}
});
expect(res.statusCode).to.equal(200);
expect(res.result).to.be.an.object();
expect(res.result.updated.name).to.equal('Updated Campaign Title');
expect(res.result.updated.maxImpression).to.equal(1000);
});
it("should delete campaign", async () => {
const res = await server.inject({
url: `/campaign/${campaignId}`,
method: 'delete',
headers: {
"Authorization": token,
}
});
expect(res.statusCode).to.equal(200);
expect(res.result.deleted).to.equal(campaignId);
const res2 = await server.inject({
url: '/campaign',
method: 'get',
headers: {
"Authorization": token,
}
});
expect(res2.statusCode).to.equal(200);
expect(res2.result.status).to.equal(true);
expect(res2.result.results).to.be.an.array();
expect(res2.result.results).to.have.length(0);
});
});

Related

How can I save request from client on server

So basically I have a api route when I request the data from client and send the data from the client that sent the request to another client. Concretely I have student user that has bought a course and I want to notify the teacher when the course is bought. When student buys lesson he sends his user_name and other data which I want to save on server and then send the data from user that sent it to the teacher.
Here is code for the
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
res.setHeader("Access-Control-Allow-Origin", "*");
const { user_name, course_id, author_id, courseName } = req.body;
const author = await fetch(
`http://localhost:8000/api/user-id/${author_id}`
).then((res) => res.json());
console.log(author.user);
const message = `Hi ${author?.user?.name}, ${user_name} has purchased your course:
${courseName}!`;
res.status(200).json({
message: {
message: message,
courseName: courseName,
buyerName: user_name,
authorName: author?.user?.name,
},
});
This is the api call from student
const handleSendMessage = async () => {
const res = await fetch(`http://localhost:3000/api/puchase-message`, {
method: "POST",
headers: {
"Content-Type": "application/json",
// disable preflight request
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify({
user_name: session?.user_name,
course_id: session?.product_id,
author_id: user_id,
courseName: session?.productName,
}),
});
};
This is api call for the teacher to get the message
const fetchMessage = async () => {
const res = await fetch(`http://localhost:3000/api/puchase-message`, {
method: "GET",
headers: {
"Content-Type": "application/json",
// disable preflight request
"Access-Control-Allow-Origin": "*",
},
});
const data = await res.json();
setMessage(data.message);
};
This is the output

how to store a auth token in react native from api responce

i am trying to store the response.data.token into sessionstorage or localstorage how can i do it from inside the axios then
const getdata = async () => {
var date2 = moment(mydate2).format('DD/MM/YYYY');
var date = moment(mydate).format('DD/MM/YYYY');
var todaydate = moment(new Date()).format('DD/MM/YYYY');
if (date == todaydate && date2 != todaydate) {
var Data56 = {
name: name,
email: email,
babyname: babyname,
phone: nuber,
period: date2,
// baby_date: date,
};
} else {
var Data56 = {
name: name,
email: email,
babyname: babyname,
phone: nuber,
// period: date2,
baby_date: date,
};
}
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/register',
data: Data56,
})
.then(async response => {
await AsyncStorage.setItem('token', `${response.data.token}`);
alert('sucess ');
})
.catch(error => {
alert(JSON.stringify(error.response.data));
});
};
i am trying to store the response.data.token into sessionstorage or localstorage how can i do it from inside the axios then
==> Update Your code like this:-
.then(function async(response) {
try{
await AsyncStorage.setItem('token', response.data.token);
}catch{
console.log("Catch Function")
}
Setting data to Asyncstorage works asynchronous so you need set with await like this:
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/register',
data: Data,
})
.then(async (response) => {
await AsyncStorage.setItem('token', `${response.data.token}`);
alert("sucess ");
})
.catch(error => {
alert(JSON.stringify(error.response.data));
});
}

how make put axios request with formData?

i tried to send data with text and file. i created formData to send it:
updateProduct(item){
let product = new FormData();
product.append('thumb', item.thumb)
product.append('weight', item.weight)
this.$store.dispatch('UPDATE_PRODUCT', product)
},
action in store:
UPDATE_PRODUCT({commit}, item){
const token = localStorage.getItem('token');
const config = {
headers: { Authorization: `Bearer ${token}`}
};
// console.log(token)
return axios.post(`${url}`, item, config)
.then((resp) => {
commit('UPDATE_PRODUCT_IN_STATE', resp)
return resp;
})
.catch((error) => {
console.log(error);
});
},
So i have 422 error. Why?

Testing API with axios - getting triggerUncaughtException(err, true /* fromPromise */);

function signup(data_var) {
const options = {
method: 'POST',
url: 'xxx',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer undefined',
},
data: data_var,
};
return axios
.request(options)
.then(function (response) {
return response;
})
.catch(function (error) {
return error;
});
}
it('should return 200 status code', async () => {
var random = Math.floor(Math.random() * 1000000);
var email = 'shadow' + random + '#gmail.com';
signup({
firstName: 'test',
lastName: 'testing',
email: email,
})
.then(function (response) {
expect(response.status)
.toBe(200);
});
});
It will create a new user but when I check status code 200 it throws this error
Error Message
>
node:internal/process/promises:245
triggerUncaughtException(err, true /* fromPromise */);
Expected: 200
Received: undefined".] {
code: 'ERR_UNHANDLED_REJECTION'
}

Hapi Lab - how do I have shared state between lab experiments

So I made up the user domain
and I've done I think a good suite
test it's like this:
var Code = require('code');
var Lab = require('lab');
var lab = exports.lab = Lab.script();
var server = require('../../');
var Jwt = require('jsonwebtoken');
var Nconf = require('nconf');
var apiConfig = Nconf.get('api');
lab.experiment('Users', function () {
var userId, payload, decoded, token;
lab.test('create joi required', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
Code.expect(result.message).to.equal('child "firstname" fails because ["firstname" is required]');
done();
});
});
lab.test('create', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
firstname: 'Fabio',
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
token = response.result.token;
payload = options.payload;
Code.expect(response.statusCode).to.equal(201);
try {
decoded = Jwt.verify(token, apiConfig.secret);
}
catch(err) {
}
console.log(decoded.scope);
Code.expect(decoded.username).to.equal(payload.username);
Code.expect(decoded.scope).to.be.an.array();
userId = decoded.jti;
done();
});
});
lab.test('create sequelize unique', function (done) {
var options = {
method: 'POST',
url: '/api/users',
payload: {
firstname: 'Fabio',
lastname: 'Bedini',
username: 'whisher',
email: 'me#ilwebdifabio.it',
password: 'mysecret'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(result.message).to.equal('username must be unique');
Code.expect(response.statusCode).to.equal(422);
done();
});
});
lab.test('update at least one required', function (done) {
var options = {
method: 'PUT',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
done();
});
});
lab.test('update no password', function (done) {
var options = {
method: 'PUT',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId,
payload: {
password: 'mysecret_update'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(422);
done();
});
});
lab.test('update not owner', function (done) {
var options = {
method: 'PUT',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId +1,
payload: {
firstname: 'Fabio_update'
}
};
server.inject(options, function(response) {
Code.expect(response.statusCode).to.equal(403);
done();
});
});
lab.test('update', function (done) {
var updatevalue = Math.random().toString(36).slice(2);
var options = {
method: 'PUT',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId,
payload: {
firstname: 'Fabio_'+updatevalue,
lastname: 'Bedini_'+updatevalue,
username: 'whisher_'+updatevalue,
email: 'me_'+updatevalue+'#ilwebdifabio.it'
}
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(200);
Code.expect(result).to.equal(1);
done();
});
});
lab.test('findById not owner', function (done) {
var options = {
method: 'GET',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId +1,
};
server.inject(options, function(response) {
Code.expect(response.statusCode).to.equal(403);
done();
});
});
lab.test('findById', function (done) {
var options = {
method: 'GET',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(200);
Code.expect(result).to.be.instanceof(Object);
Code.expect(Object.keys(result)).to.have.length(8);
done();
});
});
lab.test('destroy not owner', function (done) {
var options = {
method: 'DELETE',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId+1
};
server.inject(options, function(response) {
Code.expect(response.statusCode).to.equal(403);
done();
});
});
lab.test('destroy', function (done) {
var options = {
method: 'DELETE',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/users/'+userId
};
server.inject(options, function(response) {
var result = response.result;
Code.expect(response.statusCode).to.equal(200);
Code.expect(result).to.equal(1);
done();
});
});
});
now I made up the product domain as well and there
is some routes needed access token.
How can I test the product domain using the 'globals'
var userId, payload, decoded, token;
or what's the way to turn in this case ?
Update
after #Matt Harrison answer
var getToken = function(){
var user = {id:1,username:'abcdefghijklmnopqrstuvwxyz'};
var token = JwtUtil.getUserToken(user).token;
return token;
}
lab.experiment('Product', function () {
lab.test('create', function (done) {
var token = getToken();
console.log(token);
var options = {
method: 'POST',
headers:{'Authorization' : 'Bearer ' + token},
url: '/api/products',
payload: {
title: 'myproduct'
}
};
server.inject(options, function(response) {
var result = response.result;
console.log(result);
Code.expect(response.statusCode).to.equal(200);
// Code.expect(result.message).to.equal('child "firstname" fails because ["firstname" is required]');
done();
});
});
});
it workish I've an other problem
with
CONSTRAINT products_ibfk_1 FOREIGN KEY (userId) REFERENCES users
(id) ON UPDATE CASCADE) stack: Error: ER_NO_REFERENCED_ROW
Not sure I have understood your question correctly but I think you're asking:
How do I have shared state between lab experiments?
The simple answer is to move var userId, payload, decoded, token; into the upper "global" scope so they can be accessed everywhere.
However my advice is don't do this. Your test cases should be independent from each other. You should be able to add tests, reorder them and remove them without it affecting other test cases. Otherwise you're creating a maintenance nightmare for yourself.
If you need a resource in multiple test cases, just create a new one for each test:
lab.test('test the thing', function (done) {
var token = getToken();
expect(token).to.equal(...);
});
lab.test('test the other thing', function (done) {
var token = getToken();
expect(token).to.equal(...);
});
If you need to change a resource and then test something, that's a single test case:
lab.test('change something and then test it', function (done) {
var token = getToken();
token.prop = 'value';
expect(token.prop).to.equal('value');
});