New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trouble with db initialization for automated testing #1911

Closed
npoirey opened this Issue Feb 14, 2017 · 1 comment

Comments

Projects
None yet
2 participants
@npoirey

npoirey commented Feb 14, 2017

Hello,
I have a small problem when trying to set up automated testing for my project in which I want to do a complete reset of the database before each test.

Basically, the problem arise when I launch my (small for the moment) tests in watch mode:
NODE_ENV=test ./node_modules/mocha/bin/_mocha -t 10000 --watch **/*.spec.js*

On the first run everything seems to work as intended, tables are created and populated without issues:

POST /auth/login 200 356.336 ms - 162
error:  status=400, message=Password need to have between 8 to 30 characters // normal log of error from express
POST /users/create 400 15.932 ms - 75
        ✓ Should warn in case of password too long

but as soon as the watch is triggered (adding a space anywhere for example), I get this:

POST /auth/login 200 285.299 ms - 162
error:  Error: SQLITE_ERROR: no such table: users // definitly not normal
POST /users/create 500 4.754 ms - 141
        2) Should warn in case of password too long //test fail

I think I am doing something wrong but I can't figure it out...
Here is my code:

users.spec.js

const testDb = require('../test/databaseHelper')

describe('API /users', () => {
  before((done) => {
    testDb.build()
      .then(() => done())
      .catch(err => done(err))
  })

  beforeEach((done) => {
    testDb.seed()
      .then(() => done())
      .catch(err => done(err))
  })

  describe('Service 001 /create', () => {
      it('Should warn in case of password too long', (done) => {
        adminSession
          .post('/users/create')
          .send({ ...newUser, password: 'abcaueiaueiaeuiaueiaueiaueiaueiaueiaueiaueiauei' })
          .expect(400, {
            status: 400,
            message: 'Password need to have between 8 to 30 characters',
          })
          .end((err) => {
            if (err) return done(err)
            done()
          })
      })
     ... other tests
   })
)}

databaseHelper.js

const bookshelf = require('../models/database')
const config = require('../knexfile').test

function build() {
  return bookshelf.knex.migrate.rollback(config)
    .then(() => bookshelf.knex.migrate.latest(config))
}

function seed() {
  return bookshelf.knex.seed.run(config)
}

module.exports = {
  build,
  seed,
}

knexfile.js

module.exports = {
  ...
  test: {
    client: 'sqlite3',
    connection: { filename: ':memory:' },
    useNullAsDefault: true,
  },
}

database.js

const knex = require('knex')
const config = require('../knexfile')[process.env.NODE_ENV || 'development']
const db = knex(config)

const bookshelf = require('bookshelf')(db)

bookshelf.plugin([
  'bookshelf-camelcase',
  'registry',
])

module.exports = bookshelf

and finally a typical migration file:

exports.up = knex =>
  knex.schema.createTable('users', (table) => {
    table.increments('id')
    table.timestamps()
    table.text('callsign').notNullable()
    table.text('email').notNullable()
    table.text('password').notNullable()
    table.boolean('admin').notNullable().defaultTo(false)

    table.index('id')
    table.index('callsign')
    table.index('email')
  })

exports.down = knex => knex.schema.dropTable('users').dropIndex(['id', 'callsign', 'email'])

I tried to see knex log with DEBUG=knex.* but saw absolutly no difference between the 2 cases (first run versus subsequent runs)

It's probably something dumb but I seem blind to it right now
Thank you !

@elhigu

This comment has been minimized.

Show comment
Hide comment
@elhigu

elhigu Feb 17, 2017

Collaborator

I think this question should go to stackoverflow. Knex issue tracker should be used only for development purposes.

That aside try to make your tests work first with file based database. You are probably not understanding how sqlite inmemory databases work. https://www.sqlite.org/inmemorydb.html

Every connection you make to inmemory database creates new distinct database. So if your app is using inmemory database and your tests are trying to connect to it and reset it, the database that your app is using will not change.

I didn't see your app code there... if you are initializing the app in tests files and pass the initialized database for it, in that case you might be able to make your tests run using plain inmemorydb. In that case probably easiest way to reset it is to kill old knex instance and create a new one before each test.

Collaborator

elhigu commented Feb 17, 2017

I think this question should go to stackoverflow. Knex issue tracker should be used only for development purposes.

That aside try to make your tests work first with file based database. You are probably not understanding how sqlite inmemory databases work. https://www.sqlite.org/inmemorydb.html

Every connection you make to inmemory database creates new distinct database. So if your app is using inmemory database and your tests are trying to connect to it and reset it, the database that your app is using will not change.

I didn't see your app code there... if you are initializing the app in tests files and pass the initialized database for it, in that case you might be able to make your tests run using plain inmemorydb. In that case probably easiest way to reset it is to kill old knex instance and create a new one before each test.

@elhigu elhigu closed this Feb 17, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment