hapipal / boilerplate

A friendly, proven starting place for your next hapi plugin or deployment
https://hapipal.com
184 stars 26 forks source link

How to test? #55

Closed nagyv closed 6 years ago

nagyv commented 6 years ago

Hi,

I would like to test a hapipal project that uses Schwifty. I could create simple unit tests for the Schwifty models without actually requiring the server at all, but when I would like to test my routes I don't know how to get

Example router:

'use strict'
const Joi = require('joi')

const handler = async function (request, h) {
  // console.log('realm2', request.route.realm)
  console.log('models', request.models())
  const { Championship } = request.models()
  const rounds = await Championship.query()
    .eagerAlgorithm(Championship.JoinEagerAlgorithm)
    .eager('[matches(orderByCode).[guest_team, home_team], children, main]')
    .findById(request.params.championshipId)
  return rounds
}

module.exports = {
  method: 'GET',
  path: '/championships/{championshipId}',
  config: {
    auth: false,
    validate: {
      params: {
        championshipId: Joi.number()
      }
    }
  },
  handler
}

and the accompanying test (as I imagine it) would start somehow like:

'use strict'

const Server = require('../../../server')

// Load modules
const Championship = require('../../models/Championship')
const config = require('../championship-get')

// Test shortcuts

describe('Championship get', () => {
  let server
  beforeAll(async () => {
    server = await Server.deployment(false)  // I prefer not to listen in a test
    await server.knex().migrate.latest('../lib/migrations')  // migrations should run as per manifest, but they don't, and setting the path here is ignored for some reason
    server.route(config)
  })

  beforeEach(async () => {
    await Championship.query(server.knex()).insert({
      name: 'WSB 2018'
    })
  })

  test('calls its handler', async () => {

    const res = await server.inject({
      method: 'GET',
      url: '/championships/1',
      headers: {}
    })

    expect(res.statusCode).toEqual(200)
  })
})

The above fails as request.models() is empty.

I've figured out that models are to be parsed at the onPreStart event, but I would not start a server when I'm testing. Is there a way to still access models in requests?

devinivy commented 6 years ago

The boilerplate is designed so that await Server.deployment(false) provides you a server identical to your actual production deployment, but not listening/started. This should be ideal for testing, as you're doing: models should be available and connected to the db, migrations should run if configured that way, all your routes should exist, etc.

I'm confused by your setup because it's hard for me to imagine a situation where you would need to require a route config, model, and your deployment separately, all at the same time. For example, is this route lib/route/championship-get.js above not already defined on the server provided by await Server.deployment()? I would expect haute-couture to have added that route for you.

An aside—which version of schwifty are you using?

P.S. models are available on request.models() or server.models() as soon as they're defined using schwifty, but they aren't connected to the database until onPreStart. Luckily Server.deployment() ensures onPreStart occurs because it initializes the server (server.initialize()) even though it does not start the server.

nagyv commented 6 years ago

I've realised that the issue was the same as https://github.com/hapipal/haute-couture/issues/42

These are due to using Jest as a test runner. Moving to Lab fixed the issue.