使用玩笑和超级测试来测试koa2时,Require返回一个空对象

时间:2018-08-05 03:58:03

标签: node.js jestjs supertest koa2 objection.js

我正在学习测试,目前我使用jestsupertest来测试koa2服务器,并且我测试的功能是登录,但是在测试时我总是收到false登录功能,我发现require经过长时间调试后在我的controllers/users.js中返回了一个空对象,我不知道为什么,对此非常困惑,因为当我真正运行koa2服务器时一切正常,帮助,谢谢。

这是我的代码

user.spec.js

import server from "../../app.js"
import request from "supertest"

afterEach(() => {
  server.close() 
})

test("Failed to login if typing wrong name and password", async () => {
  const response = await request(server)
    .post("/auth/user")
    .send({
      name: "wrong",
      password: "wrong"
    })
  expect(response.body.success).toBe(false)
})

test("Successed to login if typing right name and password", async () => {
  const response = await request(server)
    .post("/auth/user")
    .send({
      name: "rignt",
      password: "right"
    })
  expect(response.body.success).toBe(true) // always received false

})

app.js

const Koa = require('koa')
const app = new Koa()
const router = require('koa-router')()
const bodyParser = require('koa-bodyparser')
const logger = require('koa-logger')
// const port = 4155
const port = 6155
const auth = require('./server/routes/auth')
const api = require('./server/routes/api')
const users = require('./server/models/users')
const path = require('path')
const serve = require('koa-static')
const mount = require('koa-mount')
const historyApiFallback = require('koa2-history-api-fallback')


// handle database
const objection = require('objection')
const Model = objection.Model
const Knex = require('knex')
const knexConfig = require('./server/config/knexfile')

// Initialize knex
const knex = Knex(knexConfig)

// Bind all Models to a knex instance
Model.knex(knex)

app.use(bodyParser())
app.use(logger())

app.use(async (ctx, next) => {
  let start = new Date()
  await next()
  let ms = new Date() - start
  console.log('%s %s - %s', ctx.method, ctx.url, ms)
})

app.on('error', (err, ctx) => {
  console.log('server error', err)
})


// api for operate
router.use('/api', api.routes())
// auth for login
router.use('/auth', async (ctx, next) => {
    let urlReg = /auth\/user$/
    if(urlReg.test(ctx.url)) {
        await next()
    } else {
        const { token } = ctx.request.body
        if(global.userTokenObj[token] === undefined) {
            const rs = await users.findToken(token)
            if(rs.length > 0) {
                global.userTokenObj[token] = 1
                await next()
            } else {
                ctx.body = {
                    code: 1001,
                    msg: "no login"
                }
            }
        } else {
            await next()
        }
    }
})

router.use('/auth', auth.routes())
app.use(router.routes())

// avoid refesh 404
app.use(historyApiFallback())
// koa static
app.use(mount('/static', serve(path.resolve('static'))))

app.use(serve(path.resolve('dist')))

module.exports = app.listen(port, () => {
  console.log(`Koa is listening in ${port}`)
})

// module.exports = app

routes / auth.js

const {
   getUserInfo,
   postUserAuth,
 } = require('../controllers/users')

const {
    postFileNode,
    postReadFile,
    postWriteFile,
    postBuildCode,
    postDownloadProject
} = require('../controllers/editCode')

const router = require('koa-router')()

router.get('/user/:id', getUserInfo)
router.post('/user', postUserAuth)

router.post('/fileNode', postFileNode)
router.post('/readFile', postReadFile)
router.post('/writeFile', postWriteFile)
router.post('/build', postBuildCode)
router.post('/download', postDownloadProject)

module.exports = router 

controllers / users.js

const users = require('../models/users') **// return empty object**
const jwt = require('jsonwebtoken') **// return empty object**

global.userTokenObj = {};

const getUserInfo = async ctx => {
  try {
    const id = ctx.params.id
    const result = await users.getUserById(id)
    ctx.body = result
  } catch (error) {
    console.log(error)
    ctx.body = `error is ${error} when get user info`
  }
}

const postUserAuth = async ctx => {
  try {
    const data = ctx.request.body // post data from request.body
    const userInfo = await users.getUserByName(data.name)

    if (userInfo != null) {
      if (userInfo.password != data.password) {
        ctx.body = {
          success: false,
          code: 2,
          info: 'wrong password'
        }
      } else {
        const userToken = {
          name: userInfo.username,
          id: userInfo.id
        }
        const secret = 'autoactivity'
        const token = jwt.sign(userToken, secret)
        global.userTokenObj[token] = userInfo.id
        const rs = await users.setTokenById(userInfo.id, token)

        ctx.body = {
          success: true,
          code: 0,
          info: 'OK',
          token
        }
      }
    } else {
      ctx.body = {
        success: false,
        code: 1,
        info: 'no users'
      }
    }
  } catch (error) {
    console.log(error)  
    ctx.body = `error is ${error} when post user auth`
  }
}

module.exports = {
  getUserInfo,
  postUserAuth,
}

models / users.js

const Model = require('objection').Model

class Users extends Model {
  // Table name is the only required property.
  static get tableName () {
    return 'users'
  }
}

const getUserById = async id => {
  try {
    const userInfo = await Users.query().findById(id)
    return userInfo
  } catch (error) {
    console.log(error)
    return error
  }
}

const getUserByName = async name => {
  try {
    const userInfo = await Users
      .query()
      .findOne({
        username: name
      })
    return userInfo
  } catch (error) {
    console.log(error)
    return error
  }
}

const setTokenById = async (id, token) => {
    try {
        const result = Users
            .query()
            .update({token})
            .where('id', id)
        return result
    } catch(error) {
        return error
    }
}
const findToken = async (token) => {
    try {
        const result = Users
            .query()
            .select()
            .where('token', token)
        return result
    } catch(error) {
        return error
    }
}
module.exports = {
  getUserById,
  getUserByName,
  setTokenById,
  findToken
}

package.json

{
  "name": "auto-activity",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "shangwenlong652 <dxcqcv@gmail.com>",
  "private": true,
  "scripts": {
    "update": "gulp",
    "debugnode": "nodemon --inspect-brk app.js",
    "start": "nodemon app.js",
    "devserver": "node app.js",
    "dev": "node build/dev-server.js",
    "server": "pm2 start app.js --name 'auto-activity'",
    "server:test": "pm2 start app.js --name 'test-auto-activity'",
    "showpm2": "pm2 show auto-activity",
    "showpm2:test": "pm2 show test-auto-activity",
    "savepm2": "pm2 save",
    "logspm2": "pm2 logs",
    "restartpm2": "pm2 restart auto-activity",
    "restartpm2:test": "pm2 restart test-auto-activity",
    "listpm2": "pm2 ls",
    "stoppm2": "pm2 stop auto-activity",
    "stoppm2:test": "pm2 stop test-auto-activity",
    "delpm2": "pm2 delete auto-activity",
    "delpm2:test": "pm2 delete test-auto-activity",
    "server:dev": "nodemon app.js",
    "newMigrate": "knex migrate:make add_name_date_type_to_projects --knexfile=./server/config/knexfile.js",
    "migrate": "knex --knexfile=./server/config/knexfile.js migrate:latest",
    "rollback": "knex --knexfile=./server/config/knexfile.js migrate:rollback",
    "build": "node build/build.js",
    "test": "jest --forceExit --runInBand"
  },
  "jest": {
    "verbose": true,
    "testURL": "http://localhost/",
    "moduleFileExtensions": [
      "js"
    ],
    "transform": {
      ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest",
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest"
    },
    "setupTestFrameworkScriptFile": "mock-local-storage",
    "coverageDirectory": "coverage",
    "collectCoverage": true,
    "coverageReporters": [
      "lcov",
      "text"
    ],
    "moduleNameMapper": {
      "@/(.*)$": "<rootDir>/src/$1"
    },
    "snapshotSerializers": [
      "<rootDir>/node_modules/jest-serializer-vue"
    ]
  },
  "dependencies": {
    "archiver": "2.1.0",
    "await-busboy": "^1.0.1",
    "axios": "^0.16.2",
    "graceful-fs": "^4.1.11",
    "jsonwebtoken": "~8.3.0",
    "knex": "~0.15.2",
    "koa": "^2.3.0",
    "koa-bodyparser": "^4.2.0",
    "koa-logger": "^3.0.1",
    "koa-mount": "~3.0.0",
    "koa-router": "^7.2.1",
    "koa-static": "~4.0.1",
    "koa2-history-api-fallback": "0.0.5",
    "lodash": "^4.17.4",
    "mariasql": "^0.2.6",
    "mysql": "^2.13.0",
    "objection": "^0.8.5",
    "recursive-copy": "^2.0.6",
    "replacestream": "^4.0.3",
    "rimraf": "^2.6.2",
    "vue": "2.4.2",
    "vue-codemirror": "^4.0.5",
    "vue-color": "^2.4.0",
    "vue-router": "^2.6.0",
    "vue-tree-halower": "^1.5.4",
    "vuetify": "^0.15.2",
    "vuex": "^2.3.1"
  },
  "devDependencies": {
    "autoprefixer": "^7.1.2",
    "babel-core": "~6.26.3",
    "babel-eslint": "^7.1.1",
    "babel-helper-vue-jsx-merge-props": "^2.0.3",
    "babel-jest": "~23.4.2",
    "babel-loader": "^7.1.1",
    "babel-plugin-array-includes": "^2.0.3",
    "babel-plugin-istanbul": "^4.1.1",
    "babel-plugin-syntax-jsx": "^6.18.0",
    "babel-plugin-transform-object-assign": "^6.22.0",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-plugin-transform-vue-jsx": "^3.7.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-stage-2": "^6.22.0",
    "babel-register": "^6.22.0",
    "babel-runtime": "^6.26.0",
    "chai": "^3.5.0",
    "chalk": "^2.3.0",
    "connect-history-api-fallback": "^1.3.0",
    "copy-webpack-plugin": "^4.0.1",
    "cross-env": "~5.2.0",
    "cross-spawn": "^5.0.1",
    "css-loader": "^0.28.0",
    "cssnano": "^3.10.0",
    "del": "^3.0.0",
    "dotenv": "~6.0.0",
    "eslint": "~5.2.0",
    "eslint-config-standard": "^6.2.1",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-html": "^3.0.0",
    "eslint-plugin-promise": "^3.4.0",
    "eslint-plugin-standard": "^2.0.1",
    "eventsource-polyfill": "^0.9.6",
    "express": "~4.16.3",
    "extract-text-webpack-plugin": "^2.0.0",
    "file-loader": "^0.11.1",
    "friendly-errors-webpack-plugin": "^1.1.3",
    "gulp": "~4.0.0",
    "gulp-decompress": "^2.0.1",
    "html-webpack-plugin": "^2.28.0",
    "http-proxy-middleware": "~0.18.0",
    "inject-loader": "^3.0.0",
    "jest": "~23.4.2",
    "jest-serializer-vue": "~2.0.2",
    "lolex": "^1.5.2",
    "mock-local-storage": "^1.0.5",
    "opn": "^5.1.0",
    "optimize-css-assets-webpack-plugin": "^2.0.0",
    "ora": "^1.2.0",
    "pm2": "~3.0.3",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "sinon": "^2.1.0",
    "sinon-chai": "^2.8.0",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.1",
    "supertest": "~3.1.0",
    "url-loader": "~1.0.1",
    "vue-jest": "~2.6.0",
    "vue-loader": "^12.1.0",
    "vue-style-loader": "^3.0.1",
    "vue-template-compiler": "2.4.2",
    "vue-test-utils": "~1.0.0-beta.11",
    "webpack": "^2.6.1",
    "webpack-bundle-analyzer": "~2.13.1",
    "webpack-dev-middleware": "^1.10.0",
    "webpack-hot-middleware": "^2.18.0",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

.babelrc

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "chrome": 42,
        "firefox": 38,
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-2"
  ],
  "plugins": ["transform-runtime", "transform-vue-jsx"],
  "env": {
    "test": {
      "presets": [["env", { "targets": { "node": "current" }} ]] ,
      "plugins": [
        "istanbul",
        "transform-object-assign",
        "array-includes",
        "transform-runtime"
      ]
    }
  }
}

以及bitbutck

上的项目完整代码

1 个答案:

答案 0 :(得分:0)

您正在尝试在测试代码的第一行从app.js导入服务器!

import server from "../../app.js"

但是在app.js中,您没有导出服务器常量。将应用程序实例传递给 http.createServer()方法后,应该导出服务器。

const server = http.createServer(app);
module.exports = server;

然后它应该工作!