Node.js 柴湾测试中的护照认证

Node.js 柴湾测试中的护照认证,node.js,authentication,integration-testing,chai,passport.js,Node.js,Authentication,Integration Testing,Chai,Passport.js,这是我第一个使用passport的项目,我对Node一般来说是新手。在使用Chai运行集成测试时,我很难将端点识别为授权端点。终点是 受使用passport和jsonwebtoken库的令牌身份验证保护。以下是导入到测试的其他文件 const chai = require('chai'); const chaiHttp = require('chai-http'); const mongoose = require('mongoose'); const should = chai.should(

这是我第一个使用passport的项目,我对Node一般来说是新手。在使用Chai运行集成测试时,我很难将端点识别为授权端点。终点是 受使用passport和jsonwebtoken库的令牌身份验证保护。以下是导入到测试的其他文件

const chai = require('chai');
const chaiHttp = require('chai-http');
const mongoose = require('mongoose');
const should = chai.should();
const { Session } = require('../models/practiceSession' );
const {User} = require('../models/user');
const { app, runServer, closeServer } = require('../app');
const { TEST_DATABASE_URL } = require('../config/mainConfig');
const {secret} = require('../config/mainConfig');
const jwt = require('jsonwebtoken');
chai.use( chaiHttp );
这是终点测试

//test the session endpoints
       it( 'should return a session with proper request', function(){
          const user = new User({
              name: 'random2',
              email: 'random2@random.com',
              password: 'Password2'
            });


          user.save( (err) => {
            if (err){
              console.log( err.message);
              }
          });

          const token = jwt.sign({
            id: user._id,
            userName: user.name,
            level: 0
            }, secret, {
            expiresIn: 60 * 60
            });

          console.log( "user id: ", user._id);
          console.log( 'token is: ', token );

          const practiceRequest = {
            operation: "+",
            number: "10",  ///this will possible need to be sent as a number
            min: "1",
            max: "200"
          };

          return chai.request(app)
            .post('/api/session')
            .set('Authorization', 'Bearer ' + token)
            .send( practiceRequest )
            .then( (res) => {
              res.should.have.status(201);
            })
          });

    });
这两条console.log语句确认正在创建用户并具有_id属性,并且正在创建有效的令牌 已创建(已在上确认)

这是端点的代码

router.route("/session")
    .post(passport.authenticate('jwt', { session: false }), jsonParser, ( req, res ) => {
        console.log( req );
        let practiceSession = [];  
        for ( let i = 0; i < req.body.number; i++ ){
            let firstTerm = generateTerm( req.body.min, req.body.max );
            let secondTerm = generateTerm( req.body.min, req.body.max );
            const problem = {  
                operator: req.body.operation,
                firstTerm,
                secondTerm,
                problem: `${ firstTerm } ${ req.body.operation } ${ secondTerm }`,
                correctResponse: generateCorrectResponse( firstTerm, secondTerm, req.body.operation )
            }; 
            practiceSession.push( problem );
        }

    // save session into db sessions collection for use in the training-logic.js
        Session
        .create( {
            userId: req.user._id, 
            problems: practiceSession  
        } )
        .then(
            session => res.status( 201 ).json( session) )
        .catch( err => {
            console.error( err );
            res.status( 500 ).json( { message: 'Internal Server Error' } );
        });
    } );
它仍然被拒绝,因为
未经授权
。从测试发送到会话终结点的请求中缺少某些内容。会话端点中的
console.log(req)
确认,与测试中从承诺链发送的内容相比,它正在接收一个添加了大量信息的对象。我必须使用外部作用域中的token变量在
chai.request(app)
命令之间传递值。这与工作应用程序中存在的数据流不同。我不知道如何测试这一点;我的理解是,到目前为止,我所尝试的并没有为端点提供足够的数据来验证请求

任何帮助都将不胜感激。谢谢你抽出时间

解决方案

接下来,一位朋友帮助我解决了这个问题,并给了我一个解决方案,当我遇到问题时,该解决方案会将附加信息传递回端点 构建令牌。最终的工作模型有一个
beforeach()
函数,该函数向测试数据库添加一个虚拟用户,然后 将此用户分配给外部作用域中的
testUser
变量,以便在以后的测试中可以访问该变量。在实际测试中 端点此
testUser
变量映射到完整的用户架构,用于构建令牌和测试端点。它运行良好,因为端点具有所需的所有属性。这是代码

describe( 'End-point for practice session resources', function() {

    let testUser;
    let modelSession; 

    before( function() {
      return runServer( TEST_DATABASE_URL );
    });

    beforeEach( function(done){
      addUser()
      .then( user => {
        testUser = user;
        done(); 
      });
    });
以及测试

 it( 'should generate a session with the proper request (POST)', function(){

          const token = jwt.sign({
            id: testUser._id
          }, secret, { expiresIn: 60 * 60 }); 

          return chai.request( app )
              .post( '/api/session' )
              .set( 'Authorization', `Bearer ${ token }` )
              .send( {
                  operation: "+",
                  number: "10",  
                  min: "1",
                  max: "200"
              })
              .then( res => { 
                res.should.have.status(201);
              } )
            })
          });
希望这能帮助其他人

解决方案

接下来,一位朋友帮助我解决了这个问题,并给了我一个解决方案,当我遇到问题时,该解决方案会将附加信息传递回端点 构建令牌。最终的工作模型有一个
beforeach()
函数,该函数向测试数据库添加一个虚拟用户,然后 将此用户分配给外部作用域中的
testUser
变量,以便在以后的测试中可以访问该变量。在实际测试中 端点此
testUser
变量映射到完整的用户架构,用于构建令牌和测试端点。它运行良好,因为端点具有所需的所有属性。这是代码

describe( 'End-point for practice session resources', function() {

    let testUser;
    let modelSession; 

    before( function() {
      return runServer( TEST_DATABASE_URL );
    });

    beforeEach( function(done){
      addUser()
      .then( user => {
        testUser = user;
        done(); 
      });
    });
以及测试

 it( 'should generate a session with the proper request (POST)', function(){

          const token = jwt.sign({
            id: testUser._id
          }, secret, { expiresIn: 60 * 60 }); 

          return chai.request( app )
              .post( '/api/session' )
              .set( 'Authorization', `Bearer ${ token }` )
              .send( {
                  operation: "+",
                  number: "10",  
                  min: "1",
                  max: "200"
              })
              .then( res => { 
                res.should.have.status(201);
              } )
            })
          });

希望这能帮助其他人

James,谢谢你的介绍,我从来没有在Node的服务器端使用过Chrome调试器。在应用程序的正常运行中,我在sessionRouter端点(如上)中设置了一个断点,并检查了请求对象。在标题中有一个用于
授权的属性:“持有者eyJhbGciOiJIUzI1NiIsIn…”
我的理解是,这就是测试中发送的内容。这个工具提供了额外的信息,但我认为它证实了我一直在做的事情。我仍然不知道为什么这个测试会因为“未经授权”而失败。再次感谢您的时间。听起来像是令牌头正在上升(这很好)。将问题缩小到JWT无效:)身份验证调用。James,感谢您的参考,我从未在节点的服务器端使用Chrome调试器。在应用程序的正常运行中,我在sessionRouter端点(如上)中设置了一个断点,并检查了请求对象。在标题中有一个用于
授权的属性:“持有者eyJhbGciOiJIUzI1NiIsIn…”
我的理解是,这就是测试中发送的内容。这个工具提供了额外的信息,但我认为它证实了我一直在做的事情。我仍然不知道为什么这个测试会因为“未经授权”而失败。再次感谢您的时间。听起来像是令牌头正在上升(这很好)。把你的问题缩小到JWT无效:)想一想澄清一下,事实上,通过回顾你的代码,你的问题很明显,你的测试中有一个竞争条件。创建用户,然后继续发送请求,然后才能确保用户已保存。我写了一个库,我认为它真的可以帮助简化您的测试,看看,它是专门为解决这样的问题而设计的。如果你对此有任何疑问,请告诉我:)太棒了!谢谢你,詹姆斯!不用担心,在我以前的工作中,我们发现自己进行了大量的集成测试,需要大量的设置,尽管Mocha很棒,但很容易陷入回调地狱或被类似于hit的场景绊倒,它现在是自动化测试过程的一个组成部分,每天都要运行数千个测试。文档中有一些简单的例子,但如果你正在努力解决这个问题,我很乐意用一个要点来“流畅地”说明你问题中的代码。想一想澄清一下,事实上,通过回顾你的代码,很明显,你的问题是你在测试中遇到了竞争条件。创建用户,然后继续发送请求,然后才能确保用户已保存。我写了一个库,我认为它真的可以帮助简化您的测试,看看,它是专门为解决这样的问题而设计的。如果你对此有任何疑问,请告诉我:)太棒了!谢谢你,詹姆斯!不用担心,在我以前的工作中,我们发现自己进行了大量的集成测试,需要大量的设置,尽管Mocha很棒,但很容易陷入回调地狱或被类似于hit的场景绊倒,它现在是自动化测试过程的一个组成部分,用于运行数千个测试