1

I have a mongoose schema-WishlistItem, which has a validation: A new WishlistItem cannot be created if it's wishlist property(an object id) doesn't belong to a real existing Wishlist in the database. The WishlistItem has this validation so that wishlistItems without parent wishlists aren't accidentally added to the database.

How can I run tests on the WishlistItem model without creating a real wishlist?

I'm using mocha and chai.

The test to create a wishlistItem

Currently the test gives: AssertionError: expected undefined to be an object.

This is because await WishlistItem.create({... throws an error:

ValidationError: WishlistItem validation failed: wishlist: Invalid WishlistItem "wishlist" property. No wishlist found with id: 5f9480a69c4fcdc78d55397d since we don't have that wishlist in the database.

const chai = require('chai');
const mongoose = require('mongoose');


const { expect } = chai;

const dbConnect = async (dsn) =>
  mongoose.connect(dsn, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useFindAndModify: false,
  });

const should = chai.should();
const WishlistItem = require('../testsFiles/WishlistItem.Model');

describe('Wishlist Item', () => {
  before(async () => {
    dbConnect(`mongodb://127.0.0.1:27017/schemaDepTest`);
  });
  context('create wishlist item', () => {
    it('should create a wishlist item with valid arguments', async function () {
      let wishlist;
      try {
        wishlist = await WishlistItem.create({
          itemName: 'Purse',
          price: '5.00',
          wishlist: mongoose.Types.ObjectId('5f9480a69c4fcdc78d55397d'),
        });
      } catch (err) {
        console.log(err);
      }
      expect(wishlist).to.be.an('Object');
    });
  });
});

WishlistItem Schema

const mongoose = require('mongoose');

const itemSchema = new mongoose.Schema(
  {
    itemName: { type: String, required: true, trim: true },
    price: { type: String, required: true, trim: true },
    wishlist: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'Wishlist',
      required: true,
    },
  },
  { timestamps: { createdAt: 'created_at' } }
);

itemSchema.path('wishlist').validate(async function (value) {
  const WishlistModel = require('./Wishlist.Model');
  const wishlist = await WishlistModel.findOne({ _id: value });
  if (!wishlist) {
    throw new Error(
      `Invalid WishlistItem "wishlist" property. No wishlist found with id: ${value}`
    );
  } else {
    return true;
  }
}, 'Parent Wishlist non existent');

const WishlistItem = mongoose.model('WishlistItem', itemSchema);
module.exports = WishlistItem;

The Wishlist Schema

const mongoose = require('mongoose');

const wishlistSchema = new mongoose.Schema(
  {
    wishlistName: {
      type: String,
      required: true,
      trim: true,
    },
    wishlistItems: [
      // reference, one-to-many
      {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'WishlistItems',
      },
    ],
    user: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User',
      required: true,
    },
  },
  { timestamps: { createdAt: 'created_at' } }
);

const Wishlist = mongoose.model('Wishlist', wishlistSchema);

module.exports = Wishlist;
Dashiell Rose Bark-Huss
  • 2,173
  • 3
  • 28
  • 48

1 Answers1

0

This post answered my question

I just had to add sinon.stub(Object.getPrototypeOf(Wishlist), 'findOne').callsFake(() => 'mock');

This way, when WishlistItem tries to validate that the Wishlist exist by calling Wishlist.findOne, () => 'mock' is called in place of findOne.

full test code:

const sinon = require('sinon');
const chai = require('chai');
const mongoose = require('mongoose');

const { expect } = chai;

const dbConnect = async (dsn) =>
  mongoose.connect(dsn, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useFindAndModify: false,
  });

const should = chai.should();
const WishlistItem = require('../testsFiles/WishlistItem.Model');
const Wishlist = require('../testsFiles/Wishlist.Model');

describe('Wishlist Item: testing dependency mocking ', () => {
  before(async () => {
    dbConnect(`mongodb://127.0.0.1:27017/schemaDepTest`);
  });
  context('create wishlist item', () => {
    it('should create a wishlist item with valid arguments', async function () {
      sinon.stub(Object.getPrototypeOf(Wishlist), 'findOne').callsFake(() => 'mock');

      let wishlist;
      try {
        wishlist = await WishlistItem.create({
          itemName: 'Purse',
          price: '5.00',
          wishlist: mongoose.Types.ObjectId('5f9480a69c4fcdc78d55397d'),
        });
      } catch (err) {
        console.log(err);
      }
      console.log(wishlist);
      expect(wishlist).to.be.an('Object');
    });
  });
});
Dashiell Rose Bark-Huss
  • 2,173
  • 3
  • 28
  • 48