0

I'm having a little trouble with an integration test for my mongoose application. The problem is, that my unique setting gets constantly ignored. The Schema looks more or less like this (so no fancy stuff in there)

const RealmSchema:Schema = new mongoose.Schema({
    Title : {
        type : String,
        required : true,
        unique : true
    },    
    SchemaVersion : {
        type : String,
        default : SchemaVersion,
        enum: [ SchemaVersion ]
    }
}, {
    timestamps : {
        createdAt : "Created",
        updatedAt : "Updated"
    }
});

It looks like basically all the rules set in the schema are beeing ignored. I can pass in a Number/Boolean where string was required. The only thing that is working is fields that have not been declared in the schema won't be saved to the db

First probable cause:

I have the feeling, that it might have to do with the way I test. I have multiple integration tests. After each one my database gets dropped (so I have the same condition for every test and precondition the database in that test).

Is is possible that the reason is my indices beeing droped with the database and not beeing reinitiated when the next text creates database and collection again? And if this is the case, how could I make sure that after every test I get an empty database that still respects all my schema settings?

Second probable cause:

I'm using TypeScript in this project. Maybe there is something wrong in defining the Schema and the Model. This is what i do.

1. Create the Schema (code from above)

2. Create an Interface for the model (where IRealmM extends the Interface for the use in mongoose)

import { SpecificAttributeSelect } from "../classes/class.specificAttribute.Select";
import { SpecificAttributeText } from "../classes/class.specificAttribute.Text";
import { Document } from "mongoose";

interface IRealm{
    Title : String;
    Attributes : (SpecificAttributeSelect | SpecificAttributeText)[];
}

interface IRealmM extends IRealm, Document {

}

export { IRealm, IRealmM }

3. Create the model

import { RealmSchema } from '../schemas/schema.Realm';
import { Model } from 'mongoose';
import { IRealmM } from '../interfaces/interface.realm';


// Apply Authentication Plugin and create Model
const RealmModel:Model<IRealmM> = mongoose.model('realm', RealmSchema);

// Export the Model
export { RealmModel }
relief.melone
  • 3,042
  • 1
  • 28
  • 57
  • how did your integration test drop the database? any specific command? – Aabid Oct 11 '18 at 13:32
  • The Test Creates has the roles dbAdmin and readWrite to a Database called "IntegrationTest" (so i dont use the productive one). My tests use the beforeEach(resetDatabase) which is basically mongoose.connection.db.dropDatabase() – relief.melone Oct 11 '18 at 14:08
  • anyone. I tried for a long time now. still not the slightest clue what's going wrong – relief.melone Oct 11 '18 at 17:07
  • Ok. I figured out the first part of the problem. https://stackoverflow.com/questions/5535610/mongoose-unique-index-not-working states a similar problem. It seems that the deprecation on ensureIndex is causing the problem so my model has to explicitly use createIndex. This only leaves me with the problem, that after a dropDatabase the indexes are gone and dont get reinitiated – relief.melone Oct 12 '18 at 07:38

2 Answers2

0

Unique options is not a validator. Check out this link from Mongoose docs.

shmit
  • 2,306
  • 2
  • 16
  • 20
0

OK i finally figured it out. The key issue is described here

Mongoose Unique index not working!

Solstice333 states in his answer that ensureIndex is deprecated (a warning I have been getting for some time now, I thought it was still working though)

After adding .createIndexes() to the model leaving me with the following code it works (at least as far as I'm not testing. More on that after the code)

// Apply Authentication Plugin and create Model
const RealmModel:Model<IRealmM> = mongoose.model('realm', RealmSchema);
RealmModel.createIndexes();

Now the problem with this will be that the indexes are beeing set when you're connection is first established, but not if you drop the database in your process (which at least for me occurs after every integration test)

So in my tests the resetDatabase function will look like this to make sure all the indexes are set

const resetDatabase = done => {
    if(mongoose.connection.readyState === 1){
        mongoose.connection.db.dropDatabase( async () => {
            await resetIndexes(mongoose.models);
            done();
        });
    } else {
        mongoose.connection.once('open', () => {
            mongoose.connection.db.dropDatabase( async () => {
                await resetIndexes(mongoose.models);
                done();
            });  
        });      
    }
};

const resetIndexes = async (Models:Object) => {
    let indexesReset: any[] = [];
    for(let key in Models){
        indexesReset.push(Models[key].createIndexes());
    }
    Promise.all(indexesReset).then( () => {
        return true;
    });   
}
relief.melone
  • 3,042
  • 1
  • 28
  • 57