Mocha chai request and express-session - session

When using two nested chai requests, session get lost.
chai.request(server)
.post('/api/v1/account/login')
.send({_email: 'test#test.com', _password: 'testtest'})
.end(function(err, res){
chai.request(server)
.get('/api/v1/user/me')
.end(function(err2, res2){
//here i should get the session, but its empty
res2.should.have.status(200);
done();
});
});
And i'm pretty sure that it's an error in my mocha test, because i tried it (the login and then retrieving the session) outside the test and the session is being setted.

express itself does not have any native session support. I guess you are using some session middleware such as https://github.com/expressjs/session.
Meanwhile, I guess you are using chai-http plugin to send HTTP request. In chai-http, in order to retain cookies between different HTTP requests (so that req.session can be available in express side), you need to use chai.request.agent rather than chai.
Here is a simple example for your code:
var agent = chai.request.agent(app);
agent.post('/api/v1/account/login')
.send({_email: 'test#test.com', _password: 'testtest'})
.then(function(res){
agent.get('/api/v1/user/me')
.then(function(res2){
// should get status 200, which indicates req.session existence.
res2.should.have.status(200);
done();
});
});
For chai.request.agent, you can refer to http://chaijs.com/plugins/chai-http/#retaining-cookies-with-each-request

In case anyone else comes across this issue, this approach worked for me using Mocha:
it("should...", () => {
return agent.post('/api/v1/account/login')
.send({_email: 'test#test.com', _password: 'testtest'})
.then(async res => {
const res2 = await agent.get('/api/v1/user/me')
res2.should.have.status(200);
})
.catch(error => {
throw error;
});
});

Related

Can you configure Cypress to log requests and responses to a file?

When I run my Cypress tests I randomly get HTTP 405 Method not allowed code when I submit the form, but the HTTP method is a correct one - POST. If I open the Developer Tools to see the outgoing request the HTTP 405 is never returned, in other words the error only happens when Developer Tools are closed. No combination of cy.pause(), cy.wait() alleviates the problem.
Question: Can you configure Cypress so it logs all the outgoing requests and responses to a file so I don't have to open DevTools?
Should be possible with cy.intercept() functional handler.
General info here Using the routeHandler function
cy.intercept(url, (req) => {
cy.writeFile('my-log', req, { flag: 'a' }) // append
req.continue((res) => {
cy.writeFile('my-log', res, { flag: 'a' }) // append
})
})
Utilizing an interceptor solely for logging purposes is not very efficient.
You can generate a HAR file that includes detailed information about the network activity during the execution of your Cypress tests.
Especially for this purpose, you can use the cypress-har-generator.
describe('my tests', () => {
before(() => {
// start recording
cy.recordHar();
});
after(() => {
// save the HAR file
cy.saveHar({ waitForIdle: true });
});
it('does something', () => {
cy.visit('https://example.com');
// ...
});
});

Sinon fakeServer with mocha and axios

I'm trying to get sinon.fakeServer to make axios return a faked response. Instead of returning the mocked payload, I can see the network request 404s or does a timeout trying to go to the actual URL.
My setup:
describe('test call', () => {
var server;
beforeEach(() => {
server = sinon.fakeServer.create();
server.respondWith(
"https://my.domain.com/myresource",
[200, { "Content-Type": "application/json" }, "[]"]
);
server.autoRespond = true
});
it('returns empty array', done => {
axios
.get('https://my.domain.com/myresource')
.then(res => {
expect(true).to.equal(true);
done()
})
.catch(err=>{
console.log(err.message);
expect(false).to.equal(true);
done();
});
});
afterEach(() => {
server.restore();
});
})
It seems that your execution environment is NodeJS, even though it's not mentioned. Others had the same issue - have a look here.
Also the Sinon team mentions that it's outside their scope since XHR are supposed to work correctly in the browser, where their fake server works as expected as it stubs the XHR object.
Axios is using a different library for making requests when running on the server, so this scenario cannot work by default. There are specific mocking libs for axios like moxios as an alternative.

Supertest .expect(200) vs. res.status.should.equal(200);

Do both of these serve the same purpose? Why are they both used in, for example, this tutorial https://codeforgeek.com/2015/07/unit-testing-nodejs-application-using-mocha/ ?
Edit, Looking at the following code:
var supertest = require("supertest");
var should = require("should");
// This agent refers to PORT where program is runninng.
var server = supertest.agent("http://localhost:3000");
// UNIT test begin
describe("SAMPLE unit test",function(){
// #1 should return home page
it("should return home page",function(done){
// calling home page api
server
.get("/")
.expect("Content-type",/json/)
.expect(200) // THis is HTTP response
.end(function(err,res){
// HTTP status should be 200
res.status.should.equal(200);
// Error key should be false.
res.body.error.should.equal(false);
done();
});
});
});
Is it necessary to have
.expect(200)
and
res.status.should.equal(200);
? What is the difference?
The .expect(200) part is using the supertest facility for verifying data. the object.should.equal(value) part is using shouldJS for verification.
I prefer utilizing shouldJS in the .end() because it allows me to do a bit of data manipulation, testing, logging, etc, as needed.
Do note the following from: https://www.npmjs.com/package/supertest
If you are using the .end() method .expect() assertions that fail will not throw - they will return the assertion as an error to the .end() callback.
So, in the example code you show above, if .expect("Content-type",/json/) or .expect(200) fails, there is nothing in the .end() to catch it. A better example would be:
var supertest = require("supertest");
var should = require("should");
// This agent refers to PORT where program is runninng.
var server = supertest.agent("http://localhost:3000");
// UNIT test begin
describe("SAMPLE unit test",function(){
// #1 should return home page
it("should return home page",function(done){
// calling home page api
server
.get("/")
.expect("Content-type",/json/)
.expect(200) // THis is HTTP response
.end(function(err,res){
// NOTE: The .expect() failures are handled by err and is
// properly passed to done. You may also add logging
// or other functionality here, as needed.
if (err) {
done(err);
}
// Error key should be false.
res.body.error.should.equal(false);
done();
});
});
});
Update to answer the question in the comment and provide a prettier response here:
Question: Would doing something like .expect(200, done) catch the error then?
Answer: The short answer is, "Yes". On the same page I quoted above, it has the following:
Here's an example with mocha, note how you can pass done straight to
any of the .expect() calls:
describe('GET /user', function() {
it('respond with json', function(done) {
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
Technically speaking there's no difference and I think you should stick to .expect(200) just like supertest examples suggest: https://github.com/visionmedia/supertest

superagent-bluebird-promise cannot GET

I'm using superagent-bluebird-promise, and the following gives me a 404 error, "cannot GET /v1/result". Have confirmed it works when I call it via Postman. What am I doing wrong?
it('should return a result', function(done){
stub.login(userId);
request.get('http://localhost:8080/v1/result/')
.then(function(res) {
console.log(res);
expect(res.body).to.have.lengthOf(1);
}, function(error) {
console.log(error);
expect(error).to.not.exist;
})
.finally(function(){
stub.logout();
done();
});
});
superagent-bluebird-promise is based on supertest
Assuming that stub.login sets some cookie, then you would require them in the next request.
For that you need an agent. (app may be optional)
var agent = request.agent(app)
agent.request(...)
Perform the login on the agent, then do the request on it too.

SailsJs :: Keep sessions with mocha

I need to keep my sessions alive between to mocha requests.
After login, I store in the user id in the express session object :
req.session.user = user.id ;
On a browser, the session is kept without any question needed (tested with Postman).
But, I need to make my REST API reachable for an external app, and I would like not to have to authenticate for each request on my API.
Is there a way for me to be able to keep the session between two requests in mocha or via the client app of the API ?
Thanks by advance.
English is not my mother langage, I may have not been as clear as I would have wanted. So I can provide any information you might need to help me.
UPDATE
Thanks to Alberto, I figured out how to keep my sessions alive in Mocha with Supertest.
An agent keeps his sessions until its it destroyed, or the logout is requested.
What needs to be donne is use the same agent to login and for requesting the API.
What I did is :
var request = require('supertest'),
should = require('chai').should();
describe('ImageController', function() {
var agent = request.agent('http://localhost:1337') ;
before(function(done){
agent
.post('/auth/local')
.send({identifier: 'email', password: 'password'})
.end(function(err, res) {
if (err) return done(err);
done();
});
})
after(function(done){
agent
.get('/logout')
.end(function(err, res) {
if (err) return done(err);
done();
});
})
describe('POST /image', function(){
it('should return 201 for image creation after login', function (done) {
agent
.post('/image')
.send({name: 'test.png'})
.end(function (err, res) {
if (err) return done(err);
res.status.should.be.equal(201);
done();
});
});
});
});
Use supertest agent feature how can store cookies.
Has one example in supertest docs: https://github.com/tj/supertest#example
Sails.js example with super test example: https://github.com/albertosouza/sails-test-example
Test file example snipplet:
var request = require('supertest');
var assert = require('assert');
var authenticated;
describe('Example test', function() {
// use efore all to create custom stub data
before(function(done) {
// use supertest.agent for store cookies ...
// logged in agent
// after authenticated requests
//login and save one agent with your session cookies. Ex:
authenticated = request.agent(sails.hooks.http.app);
authenticated.post('/auth/login')
.send({
email: user.email,
password: user.password
})
.end(function(err) {
done(err);
});
});
describe('authenticated requests', function(){
it ('should access one protected route', function(done){
// use the authenticated agent to do authenticated requests
authenticated.get('/protected')
.expect(200)
.end(function(err, res) {
if (err) return done(err);
console.log('response:', res.text);
done();
});
});
});
});

Resources