how to write tests for get requests in jest - node.js

I am testing API'S with JEST. I don't understand how I'm going to pass values to parameters in GET request.
describe("Refresh Token", () => {
it("Refresh Token", async() => {
const response = await request(app).get("/refreshtoken");
expect(response.status).toEqual(200);
expect(response.body.data).toEqual("hd$snndm12cdj2#Efvvxv");
});
})
In the above case, the output is expected as the given string. But the output is undefined. Besides that what I should do if I have multiple parameters. Below code is my post request code which is working perfectly. I want to pass multiple parameters as I defined in the post request.
describe('Set Profile Image', () => {
it('Set Profile Image', async() => {
const res = await request(app)
.post('/setProfileImage')
.send({
profileID: "1234",
profileImage: "fnsdjnfsnf"
})
expect(res.status).toBe(200)
})
});

Try passing the params in the URL of your request:
const response = await request(app).get("/refreshtoken?param1=123")
To pass multiple parameters, just do this:
const response = await request(app).get("/refreshtoken?param1=123&param2=234")

Related

How to fix an endpoint test that returns 404 status code rather than 200 using express, jest and supertest

My end goal is that I want to be able to create a test that satisfies the following statement:
verify that requests to valid URLs return a 200 HTTP status code
A valid URL for example would be /about-page or /jobs, basically any directory that I add in my content folder that contains a file with the extension /index.md.
This is my code so far:
app.js
const readFilePromise = util.promisify(fs.readFile)
app.get('/*', (req, res) => {
readFilePromise(path.join(__dirname, 'content', req.url) + '/index.md', 'utf8')
.then(data => {
convertData(data, res)
})
.catch(err => {
res.status(404).send('Page doesn\'t exist!')
})
})
const convertData = (data, res) => {
const convertedData = md.render(data)
readFilePromise(path.join(__dirname, '/template.html'), 'utf8')
.then(data => {
data = data.replace(/\{\{content\}\}/, convertedData)
res.send(data)
})
.catch(err => {
console.log(err)
})
}
app.listen(3000)
module.exports = app
After reading this article, it mentions that
Requests are asynchronous, which means you must be able to conduct asynchronous tests.
So I wrote the following test:
app.test.js
const app = require('./app.js')
const request = supertest(app)
const supertest = require('supertest')
it('Gets the test endpoint and returns a 200 status', async done => {
const res = await request.get('/*')
expect(res.status).toBe(200)
done()
})
When I run the test, it fails with a 404 status, rather than returning a 200 status. I thought this might be due to my app.js not being in the async/await style, so I changed app.js to:
const readFilePromise = util.promisify(fs.readFile)
app.get('/*', async (req, res) => {
try {
await readFilePromise(path.join(__dirname, 'content', req.url) + '/index.md', 'utf8')
} catch (err) {
res.status(404).send('Page doesn\'t exist!')
}
try {
const convertedData = md.render(data)
await readFilePromise(path.join(__dirname, '/template.html'), 'utf8')
data = data.replace(/\{\{content\}\}/, convertedData)
res.send(data)
} catch (err) {
console.log(err)
}
})
app.listen(3000)
module.exports = app
I tried running the test again, but it still fails with a 404. I think my set up within app.test.js is wrong, but I'm not sure exactly what, as I've tried using the various set ups as the article. How would I fix this?
Separately, when I try going to a URL using the async/await style in app.js, I get a ReferenceError: data is not defined error, but I'm not sure how to define data in the async/await format.
I explained here how to set up app for the test environment: supertest not found error testing express endpoint
You did not mention how you set the database environment, make sure your database is not empty. Then make your get request. but just checking status for get request is not enough because if your db is empty you will still get 200.
const response = await request(app).get("/route").send().expect(200);
expect(response.body.length).toBeGreaterThan(0)
Better approach would be connect to a different database, post your data first and then check the response
const response = await request(app).get("/api/tickets").send().expect(200);
expect(response.body.length).toEqual(2); // if you post two items
Also before you every test make sure you start with empty database inside beforeEach()

React state not updating after a post request?

I'm trying to send a post request to my backend with axios, and my backend gets the values with no problem, but I want to set a state of (sent) to true when the post request is "successfully sent", I put the setSent(true) in the .then() after the axios request. but when I send the request the state isn't updated! what could be the problem? backend gets the values and works fine though... see code bellow:
const submitHandler = () => {
axios
.post(
"/sendFeedback",
qs.stringify({
name,
email,
text,
})
)
.then(() => {
setSent(true) // doesn't work (the state is still false)
})
.catch((err) => {
err && setError(true) // works just fine!
})
}
try
const submitHandler = async () => await axios ...
because it's asynchronous process and returns a promise.

Why is axios cookie undefined?

When I try to hit an endpoint with postman everything works, so I assume the problem is probably with my axios request as when logging req.headers.cookies on server after performing this axios request the value is undefined.
Cookies in browser work as well they are set correctly.
When i performed this request in postman the value of req.headers.cookie was fine and the request has been performed without any errors.
Client code:
useEffect(() => {
(async () => {
const res = await axios.post('http://localhost:4000/refresh_token', {
withCredentials: true,
});
})();
}, []);
Server code (endpoint function):
export const validateRefreshToken = async (req, res) => {
console.log(req.headers.cookie); // undefined
const { token } = parse(req.headers.cookie);
...
};
Error message: TypeError argument str must be a string.
This error points to the parse function.
Has anyone experienced this before? Any ides on how I can fix this issue?
With Axios POST, 1st arg is the url, 2nd arg is data and the 3rd arg is for options.
Provide withCredentials: true in the 3rd argument of Axios.post
useEffect(() => {
(async () => {
const res = await axios.post('http://localhost:4000/refresh_token', {} ,{
withCredentials: true,
});
})();
}, []);

Async Request to API return undefined in Jest

I am quiet new to testing, and specifically to Jest.
I am following several tutorials in which they handle asynchronous code in the manner I am attempting. My code seems to work when I am making a custom Promise that resolves with dummy data. But when I try to use axios to fetch from an external API, Jest gets as a response undefined.
// functions2.js
const axios = require("axios")
const fetch = () => {
axios.get("https://jsonplaceholder.typicode.com/users")
.then(res => res.data)
.catch(err => err);
}
module.exports = fetch;
// functions2.test.js
describe("async operation", ()=>{
it("should be defined", ()=>{
expect(fetch).toBeDefined()
}); // Passed
it("should fetch", async () => {
expect.assertions(1);
const data = await fetch();
expect(data).toBeTruthy();
}) // Did not pass, data is undefined
it("should fetch, using promises", () => {
expect.assertions(1);
return fetch().then(data => {
expect(data).toBeTruthy();
}) // Did not pass, got 0 assertions
})
})
In one tutorial I encountered that this has something to do with Jest running through Node.JS, but I don't know how to handle it because I don't know node.js.
Also, I followed a tutorial by Traversy Media, cloned his Git repo (https://github.com/bradtraversy/jest_testing_basics) and had the same problem (though in the video it worked)
The problem is because you are not returning the promise from fetch.
Update your functions2.js to something like:
const fetch = async () => {
return axios
.get("https://jsonplaceholder.typicode.com/users")
.then(res => res.data)
.catch(err => err);
};

Puppeteer: How to listen to a specific response?

I'm tinkering with the headless chrome node api called puppeteer.
I'm wondering how to listen to a specific request response and how to act in consequence.
I have look at events requestfinish and response but it gives me all the request/responses already performed in the page.
How can I achieve commented behaviour?
One option is to do the following:
page.on('response', response => {
if (response.url().endsWith("your/match"))
console.log("response code: ", response.status());
// do something here
});
This still catches all requests, but allows you to filter and act on the event emitter.
https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#event-response
Filtered response (wait up to 11 seconds) body parsed as JSON with initially requested PATCH or POST method every time you will be call that:
const finalResponse = await page.waitForResponse(response =>
response.url() === urlOfRequest
&& (response.request().method() === 'PATCH'
|| response.request().method() === 'POST'), 11);
let responseJson = await finalResponse.json();
console.log(responseJson);
Since puppeteer v1.6.0 (I guess) you can use page.waitForResponse(urlOrPredicate[, options])
Example usage from docs:
const firstResponse = await page.waitForResponse('https://example.com/resource');
const finalResponse = await page.waitForResponse(response =>
response.url() === 'https://example.com' && response.status() === 200
);
return finalResponse.ok();
I was using jest-puppeteer and trying to test for a specific response code of my test server. page.goto() resolves to the response of the original request.
Here is a simple test that a 404 response is returned when expected.
describe(`missing article page`, () => {
let response;
beforeAll(async () => {
response = await page.goto('http://my-test-server/article/this-article-does-not-exist')
})
it('has an 404 response for missing articles', () => {
expect(response.status()).toEqual(404)
})
it('has a footer', async () => {
await expect(page).toMatch('My expected footer content')
})
})
to get the xhr response simply do :
const firstResponse = await page.waitForResponse('https://example.com/resource')
// the NEXT line will extract the json response
console.log( await firstResponse.json() )

Resources