Passing request body to post using super-test
Asked Answered
H

2

16

I'm testing an express server using super-test and I need to test a post call. I assume the post should be successful and return a status of 200 but it is returning 401. I've been told by someone that I need to pass a request body with the post but I'm unsure exactly how to do this.

I've attempted to use .send({name: 'aName'}) but that gives me the same 401 code.

Below is the app.js

require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const hateoasLinker = require('express-hateoas-links');
const AValidator = require('./AValidator');
const BValidator = require('./BValidator');
const schema_v1 = require("./schema.json");
const {
    logService: logger
} = require("@utils");

let aValidator = AValidator(schema_v1);

let ValidatorApi = BValidator.ValidatorApi('api');
let adminValidator = BValidator.ValidatorAdmin('admin');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(hateoasLinker);

app.post('/*/activate',admiValidator, (req, res) => {
    console.log("In Activate===============>");
    res.status(200);
    res.json({
        rel: "self",
        method: "POST",
        title: 'Activate Solution',
        href: "/activate"
    });
});

Here is the code for the BValidator

ValidatorAdmin = function(callType){
    return function (req,res,next){
        let authoizationHeader = req.headers['authorization'];
        try {
        Verifier.verifyPayload(authoizationHeader, callType, (verificationError) => {
            if (verificationError) {
                res.setHeader('Content-Type', 'application/json');
                res.status(401);
                res.json({
                    message : "verificationError "+verificationError.message
                });
            } else {
                next();
            }
        });
        } catch (authorizationError) {
            res.setHeader('Content-Type', 'application/json');
            res.status(401);
            res.json({
                message : authorizationError.message
            });

        }
    }
}

Here is the app.test.js

const request = require('supertest');
const bodyParser = require('body-parser');
let AValidator = require('../src/AValidator');
let BValidator = require('../src/BValidator');
BValidator = jest.fn();
AValidator = jest.fn();
app = require('../src/app');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

describe('Test os GET/POST calls in app.js', ()=>{

  test('Tests activate post', (done)=>{

    BValidator.mockReturnValue({
      ValidatorApi: (req,res,next)=>{
        next();
      },
      ValidatorAdmin:(req,res,next)=>{
        next();
      }
    });

    AValidator.mockImplementation((schema)=>{
      return function (req,res,next){
        next();
      }
    });


    request(app)
      .post('/test/activate')
      .set({name:'josh'})
      .then((response)=>{
        expect(response.statusCode).toBe(200);
        done();
      })

  })


});

So ultimately I'd like this post to resolve successfully and return a status code of 200.
Handcart answered 29/3, 2019 at 19:40 Comment(24)
You probably need .post('/test/activate', {name: 'josh'}).. and remove the .setEducate
unfortunately that doesn't work either :-(Handcart
Okay, just looked at supertest docs. If .send didn't work, then theres a problem with the admiValidator. Im assuming it expects a token or something in the header of the request, and if there isn't returns 401 unauthorized.Educate
Well I did just notice that when i use .send I get a 400 error instead of a 401. So I guess that's a change at leastHandcart
Have you tried testing out the endpoint manually in postman?Educate
No. I may go that route. the person I'm testing the code for seems pretty sure this is what I need to do but I may try thatHandcart
Run in debug mode, set some breakpoints and step through to see whats going on. If non of your breakpoints are being hit, then you need to debug the admiValidator middleware, because thats where it is failing.Educate
Well the admiValidator is mocked out by the ValidatorAdmin so it should only hit that next()Handcart
Also reading supertest api, .set will set request header fields. .send will add fields to body of the request.Educate
Yeah idk, your best bet is to manually test and set breakpoints in the endpoint to see whats going on first.Educate
BTW, if you're getting a 401, there is a 100% chance its your middleware, because you aren't sending back a 401 in your code. admiValidator is being hit regardless of what you've got set in your test classEducate
Yea I'm looking at it and it seems the middleware isnt getting mocked. Good eyeHandcart
Yeah again idk what admiValidator is doing without seeing the code, but its expecting a header or something with the value 'admin', so in the test you have to pass that with the request.Educate
Now should that matter if I mock it like I intended above? I'll post the validator code thoughHandcart
@IsaacVidrine so I added that code and yea I noticed that the actual function was getting called instead of the mock. That 401 is coming from Verifier.verifyPayload which causes an error. But since I'm unit testing I shouldn't really be dealing with that and the whole ValidatorAdmin should be mocked out...in theory.Handcart
Idk what .mockReturnValue and .mockImplementation is doing, but I know it doesn't matter what you have there because admiValidator will always get called on every request to your endpoint. But yeah, definitely add the validator code.Educate
well the admiValidator is BValidator.ValidatorAdmin which is why I'm mocking itHandcart
Okay, your middleware is expecting a header field called authorization. If it exists, it then calls Verifier.verifyPayload.... so if you can post that code too.Educate
It doesn't matter that you're calling .mockReturnValue and .mockImplementation in your test, because if the request being sent doesn't have the header field authorization and a correct value, you're going to always get a 401. You have to set the correct request header in the testEducate
Unfortunately I don't have that code available to me. But shouldn't I be able to stub the function that is assigned to admiValidator thus keeping it from ever reaching Verifier.verifyPayload? I guess my point is I don't want that middleware to ever truly be called, just a mock that returns next()Handcart
Post code for BValidator.mockReturnValue and AValidator.mockImplementationEducate
Sorry the code above for Validator is BValidator that was a typo. The AValidator doesn't come into play hereHandcart
Post code/definition of BValidator.mockReturnValue... that is where the truth lies.Educate
well the code that is there is the code for it. .mockReturnValue is a function provided by jest that allows you to mock the return value of a functionHandcart
B
32

I am assuming you have set the parser correctly. Example:

 const app = express();
 app.use(bodyParser.json());
 app.use(bodyParser.urlencoded({extended: true}));

Once this is set, I believe you're missing the headers. Example:

const payload = {name: 'john', email: '[email protected]', password: '2342388' };
const res = await request(app)
            .post('/api/register')
            .send(payload)
            .set('Content-Type', 'application/json')
            .set('Accept', 'application/json')
Blowzed answered 20/9, 2022 at 12:18 Comment(0)
E
-3

Your problem is that you have a wrong understanding of what those mock functions are doing. First of all, you are completely overwriting the original values of AValidator and BValidator with jest.fn().

So doing

let AValidator = require('../src/AValidator');
let BValidator = require('../src/BValidator');

in your test is redundant.

The purpose of mockReturnValue is so that you can call that function and get back the return value you specified.

Taken straight from Jest docs

const myMockFn = jest
  .fn()
  .mockReturnValue('default')
  .mockReturnValueOnce('first call')
  .mockReturnValueOnce('second call');

// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());

You are never using or calling your mock functions, and furthermore your api has no clue they even exist.

The solution is to provide the appropriate headers in the request when you run your tests so they don't fail in the middleware. Also, to do that, you have to know what Verifier.verifyPayload is doing.

with supertest your request should look like

request(app)
.post('/test/activate')
.set({authorization: 'a_valid_value_goes_here'})
.then((response)=>{
   expect(response.statusCode).toBe(200);
   done();
})
Educate answered 29/3, 2019 at 21:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.