[Mongoose][timekeeper] TypeError: Undefined type `FakeDate` at `fieldName`
Node.js + Mongoose な構成のウェブサービスのテストコードで timekeeper という時間操作モジュールを利用していて FakeDate でハマったことをご紹介します。
timekeeper.freeze と new mongoose.Schema でエラーが発生するテストコード
'use strict';
const mongoose = require("mongoose");
const timekeeper = require("timekeeper");
describe("FakeDate error", () => {
timekeeper.freeze(new Date());
let schema = new mongoose.Schema({
createdAt: {
type: Date
}
});
timekeeper.reset();
});
エラーメッセージ TypeError: Undefined type FakeDate
$ mocha test.js
/Users/username/works/myapp/node_modules/mongoose/lib/schema.js:483
throw new TypeError('Undefined type `' + name + '` at `' + path +
^
TypeError: Undefined type `FakeDate` at `createdAt`
Did you try nesting Schemas? You can only nest using refs or arrays.
at Function.Schema.interpretAsType (/Users/username/works/myapp/node_modules/mongoose/lib/schema.js:483:11)
at Schema.path (/Users/username/works/myapp/node_modules/mongoose/lib/schema.js:415:29)
at Schema.add (/Users/username/works/myapp/node_modules/mongoose/lib/schema.js:310:12)
at new Schema (/Users/username/works/myapp/node_modules/mongoose/lib/schema.js:88:10)
at Suite. (/Users/username/works/myapp/test.js:8:16)
at context.describe.context.context (/Users/username/works/myapp/node_modules/mocha/lib/interfaces/bdd.js:73:10)
at Object. (/Users/username/works/myapp/test.js:6:1)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (/Users/username/works/myapp/node_modules/coffee-script/lib/coffee-script/coffee-script.js:211:36)
at Function.Module._load (module.js:300:12)
at Module.require (module.js:353:17)
at require (internal/module.js:12:17)
at /Users/username/works/myapp/node_modules/mocha/lib/mocha.js:157:27
at Array.forEach (native)
at Mocha.loadFiles (/Users/username/works/myapp/node_modules/mocha/lib/mocha.js:154:14)
at Mocha.run (/Users/username/works/myapp/node_modules/mocha/lib/mocha.js:326:31)
at Object. (/Users/username/works/myapp/node_modules/mocha/bin/_mocha:350:7)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:974:3
timekeeper が以下のように JavaScript の Date オブジェクトと、timekeeper で独自定義した FakeDate オブジェクトを入れ替える処理をしています。
/** * Replace the `Date` with `FakeDate`. */ function useFakeDate() { Date = FakeDate }/**
- Restore the
Date
toNativeDate
. */ function useNativeDate() { Date = NativeDate }
Date が Date でなく FakeDate に入れ替わってるタイミングで、new mongoose.Schema を呼び出すが FakeDate は MongooseTypes に定義されていない SchemaType なので例外が投げられてるっていう感じです。ザックリ説明すると。
new mongoose.Schema で SchemaType チェックしている Mongoose のコードはこの辺です lib/schema.js#L652-L671
timekeeper.freeze して timekeeper.reset するまでの間に、明示的に new mongoose.Schema したいテストコードを書くことはほぼないと思ってます。なので、new mongoose.Schema の処理を書いてる Model を定義してる module などは事前に require() しておくことでエラーを退避したいですね。