hapipal / schwifty

A model layer for hapi integrating Objection ORM

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Joi.attempt(config, Schema.schwifty) validation fails in Jest tests

kmenshov opened this issue · comments

I'm getting a Joi validation error on configuration object inside the internals.schwifty when trying to create a server inside Jest tests. Everywhere else (including NODE_ENV=test npm start) the server is being created just fine. The error disappears if I don't export any models.

Details and steps to reproduce:

// package.json

"scripts": {
    "test:jest": "NODE_ENV=test jest",
}

In any Jest test file:

// example.test.js

const Glue = require('glue');
const Manifest = require('../server/config/manifest');

const createServer = Glue.compose(Manifest.get('/'));

test('some test', async () => {
  const server = await createServer;
});

the command npm run test:jest -- example.test.js fails with the following:

ValidationError: {
      "knex": {
        "debug": false,
        "client": "pg",
        "connection": {
          "host": "127.0.0.1",
          "user": "user",
          "password": "password",
          "database": "db_test"
        }
      },
      "models": [
        function Users() {\n    _classCallCheck(this, Users);\n\n    return _possibleConstructorReturn(this, _getPrototypeOf(Users).apply(this, arguments));\n  } [2]
      ],
      "migrationsDir": "/server/config/migrations",
      "value" [1]: -- missing --
    }
    
    [1] "value" must be a Function
    [2] "0" must be a class

      at Object.<anonymous>.exports.process (node_modules/joi/lib/errors.js:203:19)
      at Object.<anonymous>.internals.Alternatives._validateWithOptions (node_modules/joi/lib/types/any/index.js:764:31)
      at Object.<anonymous>.module.exports.internals.Any.root.validate (node_modules/joi/lib/index.js:147:23)
      at Object.<anonymous>.module.exports.internals.Any.root.attempt (node_modules/joi/lib/index.js:177:29)
      at Object.<anonymous>.internals.schwifty (node_modules/schwifty/lib/index.js:190:18)
      at Object.register (node_modules/schwifty/lib/index.js:79:19)
      at Object.<anonymous>.internals.Server.register (node_modules/hapi/lib/server.js:453:35)

but if I transform the test file into a plain JS script:

// example.js

const Glue = require('glue');
const Manifest = require('../server/config/manifest');

const createServer = Glue.compose(Manifest.get('/'));

(async () => {
  const server = await createServer;
  console.log(server);
})();

and run it with NODE_ENV=test node example.js everything works fine and I see the server object being printed to stdout without any errors.

The error also disappears if I export an empty array for models:

// /server/models/index.js

const Users = require('./Users');

module.exports = [
  // Users,
];

I'm using Schwifty 4.2.0

Curious! Is jest configured to use any sort of transpilation (e.g. via babel)?

Ah, why didn't I think about it! Indeed it is:

// test/jest.setup.js
require('@babel/polyfill');

But without it I get the ReferenceError: regeneratorRuntime is not defined in tests. :(

Yep, seems like it's mutually exclusive. I've tried to replace babel polyfill with regenerator-runtime:

// test/jest.setup.js

// require('@babel/polyfill');
require('regenerator-runtime/runtime');

and got the same Joi validation error as described in the first post.

Can maybe the Joi schema be made less restrictive?

// schwifty/lib/schema.js

// internals.model = Joi.func().class();
internals.model = Joi.func();

There's really no need to transpile classes away in nodejs, and I highly suggest testing the code you're going to run in production, which I hope is not transpiled for a variety of reasons. I think the fix here is to your project's test suite. Mostly likely the polyfill itself is not responsible for the transpilation of classes to functions—you likely have @babel/preset-env setup somewhere, and you can try to configure that to omit certain transformations, or to only transpile your client-side directories.

I was wrong, sorry for bothering you. :) For anyone facing the same problem: indeed, the solution is just to exclude the server (but not the client) code from being transpiled altogether:

// jest.config.js

transformIgnorePatterns: ['<rootDir>/server/', '<rootDir>/node_modules/'],

See details here: https://jestjs.io/docs/en/configuration#transformignorepatterns-array-string

Glad you got it sorted out!