错误:预期200“OK”,尝试使用mocha登录时获得401“未授权”

时间:2017-04-26 12:49:26

标签: javascript authentication mocha passport.js

我正在尝试使用passport passport-jwtpassport-local为安全API提供用户身份验证,测试导致了一些问题。我正在尝试测试,当我使用授权标题集调用/meals时会返回一份膳食列表。

目前在mocha中,当我尝试运行我的套件时,我得到Error: expected 200 "OK", got 401 "Unauthorized",我无法理解为什么。

以下代码段:

meals.test.js

// NPM imports
const request = require('supertest');
const expect = require('expect');
const {ObjectID} = require('mongodb');

// Local files
const app = require('./../app');
const {Meal} = require('./../models/meal');
const {meals, validUsers, populateUsers, populateMeals} = require('./seed/seed');

function createAuthenticatedRequest(loginDetails, done) {
    let authenticatedRequest = request.agent(app);
    authenticatedRequest
        .post('/login')
        .send(loginDetails)
        .end(function (error, response) {
            if (error) {
                throw error;
            }
            done(authenticatedRequest)
        });
}

beforeEach(populateMeals);
beforeEach(populateUsers);


describe('GET /meals', () => {
    it('should get all the meals', (done) => {
        createAuthenticatedRequest({email: validUsers[0].email, password: 'secret'}, function (request) {
            console.log()
            request
                .get('/meals')
                .expect(200)
                .expect((res) => {
                    expect(res.body.length).toBe(2);
                })
                .end(done);
        })
    });
});

describe('POST /meals', () => {
    it('should create a new meal', (done) => {
        let mealName = 'Casserole';
        let cookedWeight = 1000;
        let servings = 5;
        let portionSize = 200;

        request(app)
            .post('/meals')
            .send({
                mealName,
                cookedWeight,
                servings
            })
            .expect(200)
            .expect((res) => {
                expect(res.body.mealName).toBe(mealName);
                expect(res.body.cookedWeight).toBe(cookedWeight);
                expect(res.body.servings).toBe(servings);
                expect(res.body.portionSize).toBe(portionSize);
            })
            .end((err) => {
                if (err) {
                    return done(err);
                }
                Meal.find({mealName}).then((meals) => {
                    expect(meals.length).toBe(1);
                    expect(meals[0].mealName).toBe(mealName);
                    done();
                }).catch((e) => done(e))
        });
    });

    it('should not create a meal with incorrect data', (done) => {
        let mealName = 'Casserole';
        let cookedWeight = 'falafel';
        let servings = 5;
        request(app)
            .post('/meals')
            .send({
                mealName,
                cookedWeight,
                servings
            })
            .expect(400, done);
    });

    it('should not create a meal with no data sent', (done) => {
        request(app)
            .post('/meals')
            .send({})
            .expect(400, done);
    });
});

describe('GET /meals/:id', () => {
    it('should return a specific meal', (done) => {
        request(app)
            .get(`/meals/${meals[0]._id.toHexString()}`)
            .expect(200)
            .expect((res) => {
                expect(res.body.meal.mealName).toBe(meals[0].mealName);
            })
            .end(done);
    });
    it('should return a 404 if not found', (done) => {
        request(app)
            .get('/meals/asd')
            .expect(404)
            .end(done);
    });
    it('should return a 404 if doc not found', (done) => {
        let hexId = new ObjectID().toHexString();

        request(app)
            .get(`/meals/${hexId}`)
            .expect(404)
            .end(done);
    });
});

describe('DELETE /meals/:id', () => {
    it('should delete a meal', (done) => {
        let hexId = meals[0]._id.toHexString();
        request(app)
            .delete(`/meals/${meals[0]._id.toHexString()}`)
            .expect(200)
            .expect((res) => {
                expect(res.body.meal._id).toBe(hexId);
            })
            .end((err) => {
                if(err) {
                    return done(err)
                }
                Meal.findById(hexId).then((meal) => {
                    expect(meal).toNotExist();
                    done();
                }).catch((e) => done(e));
            })
    });

    it('should return a 404 if meal not found', (done) => {
        let hexId = new ObjectID().toHexString();
        request(app)
            .delete(`/meals/${hexId}`)
            .expect(404)
            .end(done);
    });

    it('should return a 404 if malformed id is sent', (done) => {
        request(app)
            .delete('/meals/123abc')
            .expect(404)
            .end(done);
    });

});

describe('PATCH /meals/:id', () => {
    it('should update a meal if a valid request is sent', (done) => {
        let id = meals[0]._id.toHexString();
        let mealName = 'Testing update route';

        request(app)
            .patch(`/meals/${id}`)
            .send({
                mealName
            })
            .expect(200)
            .expect((res) => {
                expect(res.body.meal.mealName).toBe(mealName);
            })
            .end(done);
    });

    it('should return a 404 if meal is not found', (done) => {
        let id = new ObjectID().toHexString();
        let mealName = 'Testing update route';
        request(app)
            .patch(`/meals/${id}`)
            .send({ mealName })
            .expect(404)
            .end(done);
    });

    it('should return a 404 if malformed id is sent', (done) => {
        request(app)
            .patch('/meals/123abc')
            .expect(404)
            .end(done);
    });
});

路由/ meals.js

require('./../config/passport');

const express = require('express');
const router = express.Router();
const passport = require('passport');

const AuthenticationController = 
require('./../controllers/authentication/authentication');

// Middleware to require login/auth
const requireAuth = passport.authenticate('jwt', { session: false });
const requireLogin = passport.authenticate('local', { session: false });


const {listMeals, getMeal, createMeal, updateMeal, deleteMeal} = 
require('./../controllers/meals/meals');

router.get('/', requireAuth, listMeals);

router.post('/', createMeal);

router.get('/:id', getMeal);

router.delete('/:id', deleteMeal);

router.patch('/:id',  updateMeal);

module.exports = router;

控制器/餐/ meals.js

const {ObjectID} = require('mongodb');
const _ = require('lodash');

const {Meal} = require('./../../models/meal');

let listMeals = (req, res) => {
    console.log(req.headers);
    Meal.find({

    }).then((meals) => {
        res.send(meals)
    }, (e) => {
        res.status(400).send(e);
    });

};

let getMeal = (req, res) => {
    let id = req.params.id;
    if(!ObjectID.isValid(id)) {
        return res.sendStatus(404);
    }
    Meal.findOne({
        _id : id
    }).then((meal) => {
        if(!meal) {
            return res.sendStatus(404);
        }
        res.status(200).send({meal})
    }, () => {
        res.status(404).send();
    });

};

let createMeal = (req, res) => {
    let meal = new Meal({
        mealName : req.body.mealName,
        cookedWeight : req.body.cookedWeight,
        servings : req.body.servings,
        portionSize: req.body.cookedWeight / req.body.servings
    });

    meal.save().then((doc) => {
        res.send(doc)
    }, (e) => {
        res.status(400).send(e);
    });
};

let deleteMeal = (req, res) => {
    let id = req.params.id;
    if(!ObjectID.isValid(id)) {
        return res.sendStatus(404);
    }
    Meal.findOneAndRemove({
        _id : id
    }).then((meal) => {
        if(!meal) {
            return res.sendStatus(404);
        }
        res.status(200).send({meal});
    }).catch((e) => {
        res.sendStatus(400).send(e);
    });
};

let updateMeal = (req, res) => {
    let id = req.params.id;
    let body = _.pick(req.body, ['mealName', 'servings', 'cookedWeight']);
    if(!ObjectID.isValid(id)) {
        return res.sendStatus(404);
    }
    Meal.findOneAndUpdate({
        _id : id
    }, { $set : body}, {new : true}).then((meal) => {
        if(!meal) {
            return res.sendStatus(404);
        }
        res.status(200).send({meal});
    }).catch((e) => {
        res.status(400).send(e);
    })
};

module.exports = {
    createMeal,
    listMeals,
    getMeal,
    deleteMeal,
    updateMeal
};

如果需要更多信息,请告诉我

1 个答案:

答案 0 :(得分:1)

因此经过两天的戳戳和刺激后,我找到了一个解决方案,在此发布以供将来参考,创建了以下函数来创建Authorization标头并将其返回以供请求使用。

// Auxiliary function.
function createLoginToken(server, loginDetails, done) {
    request(server)
        .post('/login')
        .send(loginDetails)
        .end(function(error, response) {
            if (error) {
                throw error;
            }
            let loginToken = response.body.token;
            done(loginToken);
        });
}

然后如下调用:

it('should get all the meals', (done) => {
    createLoginToken(app, { email: validUsers[0].email, password: 'secret'}, function(header) {
        request(app)
            .get('/meals')
            .set('Authorization', header)
            .expect(200)
            .expect((res) => {
                expect(res.body.length).toBe(2);
            })
            .end(done);
    });
});

非常感谢Juha Hytönen他的博客文章指出了我正确的方向