When scaffolding a Nuxt app using create-nuxt-app, there's an option to add both a backend server and a testing framework.
I've chosen Express as by backend framework, and Jest as my testing framework, which allows me to runs tests with Jest perfectly. However, there's no server-side test example available in which you can test API end points.
I've create an api endpoint /api/threads and tried testing it with something like this:
const request = require('supertest')
const app = require('../app')
describe('GET /api/threads', () => {
it('should return 200', async () => {
await request(app)
.get(`/api/threads`)
.expect(200)
})
})
But am returned with the error: VueRenderer is not a constructor
I also made sure to export app.js, which currently looks like:
require('dotenv-safe').load()
const path = require('path')
const express = require('express')
const consola = require('consola')
const bodyParser = require('body-parser')
const bcrypt = require('bcryptjs')
const session = require('express-session')
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy
const SequelizeStore = require('connect-session-sequelize')(session.Store)
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY)
const { Nuxt, Builder } = require('nuxt')
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
const sequelize = require('./sequelize')
const models = require('./models')
const router = require('./router')
const controllers = require('./controllers')
const app = express()
config.dev = !(
process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test'
)
function addSessions() {
const sessionStorage = new SequelizeStore({
db: sequelize
})
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
store: sessionStorage
})
)
app.use(passport.initialize())
app.use(passport.session())
sessionStorage.sync()
}
function addLocalStrategy() {
passport.use(
new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password'
},
async (email, password, done) => {
try {
let user = await models.User.findOne({ where: { email } })
if (!user)
return done(null, false, {
message: 'Incorrect email.'
})
user = user.toJSON()
const passValid = await bcrypt.compare(
password,
user.password.toString('utf8')
)
if (passValid === false)
return done(null, false, {
message: 'Incorrect password.'
})
if (user && user.subscriptionId) {
const subscription = await stripe.subscriptions.retrieve(
user.subscriptionId
)
user.subscriptionStatus = subscription.status
}
return done(null, user)
} catch (err) {
console.log(err)
return done(err)
}
}
)
)
passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser(async (id, done) => {
try {
const user = await models.User.findById(id)
done(null, user)
} catch (err) {
throw new Error(err)
}
})
}
async function start() {
try {
const nuxt = new Nuxt(config)
const { host, port } = nuxt.options.server
// Build only in dev mode
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
} else {
await nuxt.ready()
}
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
addSessions()
addLocalStrategy()
app.use('/', router)
app.use('/private', controllers.User.authenticate)
app.use('/private', express.static(path.join(__dirname, 'private')))
// Give nuxt middleware to express
app.use(nuxt.render)
app.listen(port, host)
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true
})
} catch (err) {
throw new Error(err)
}
}
start()
module.export = app
Essentially it's the scaffolded server/app.js, but with code for sessions and authentication.
Any ideas on how to successfully receive a 200 response when hitting a backend API endpoint with a Nuxt / Express combo?
Once you create an instance of Nuxt which you store inside the nuxt variable. you can try printing it out to see whats there. The nuxt.server.app is the object you can feed to supertest in order to test API endpoints.
const { resolve } = require('path')
const { Nuxt, Builder } = require('nuxt')
const request = require('supertest')
// We keep the nuxt and server instance
// So we can close them at the end of the test
let nuxt = null
// Init Nuxt.js and create a server listening on localhost:4000
beforeAll(async () => {
const config = {
dev: process.env.NODE_ENV === 'production',
rootDir: resolve(__dirname, '../'),
mode: 'universal',
}
nuxt = new Nuxt(config)
await new Builder(nuxt).build()
await nuxt.server.listen(3000, 'localhost')
}, 30000)
// Example of testing only generated html
describe('GET /', () => {
test('Route / exits and render HTML', async () => {
const { html } = await nuxt.renderRoute('/', {})
expect(html).toContain('welcome')
})
})
describe('GET /', () => {
test('returns status code 200', async () => {
const response = await request(nuxt.server.app).get('/')
expect(response.statusCode).toBe(200)
})
})
describe('GET /test', () => {
test('returns status code 404', async () => {
const response = await request(nuxt.server.app).get('/test')
expect(response.statusCode).toBe(404)
})
})
// Close server and ask nuxt to stop listening to file changes
afterAll(() => {
nuxt.close()
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With