javascript - 尝试使用 mocha 登录时出现错误 : expected 200 "OK", 得到 401 "Unauthorized"

标签 javascript authentication mocha.js passport.js

我正在尝试使用 passport passport-jwtpassport-local 为安全 API 提供用户身份验证,测试是给我带来一些问题。我目前正在尝试测试当我使用授权 header 集调用 /meals 时会返回餐食列表。

目前在 Mocha 中,当我尝试运行我的套件时,我收到错误:预期 200“OK”,得到 401“未经授权”,但我不明白为什么。

代码片段如下:

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);
    });
});

routes/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;

controllers/meals/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
};

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

最佳答案

经过两天的摸索和刺激,我找到了一个解决方案,发布在这里供其他人将来引用,创建了以下函数来创建授权 header 并将其返回以供请求使用。

// 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他的博客文章为我指明了正确的方向

关于javascript - 尝试使用 mocha 登录时出现错误 : expected 200 "OK", 得到 401 "Unauthorized",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43634736/

相关文章:

javascript - 在 spring Controller 中使用 angularJs $http 将对象作为 json 键发送返回 null

javascript - 用于可点击图像的 TinyMCE WordPress 插件

javascript - 使用 Jest 进行异步 Javascript 代码测试在不应该的情况下可以正常工作

android - 流行的应用程序如何验证从他们的移动应用程序到他们的服务器的用户请求?

ruby-on-rails - 在 Rails 中使用 Mocha 测试 form_for 路径生成

javascript - JQuery - 如果链接没有 URL,则将 div 设置为隐藏

PHP MySql 用户帐户绕过 cookie

java - 使用 Twitter 身份验证验证用户

node.js - 类型错误 : Cannot read property 'drop' of undefined

angularjs - 为什么我在重新排列文件结构时得到 `MissingSchemaError`?