ts-patch-mongoose
Version:
Patch history & events for mongoose models
401 lines (306 loc) • 12.5 kB
text/typescript
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
import mongoose, { model } from 'mongoose'
import em from '../src/em'
import { toObjectOptions } from '../src/helpers'
import { patchHistoryPlugin } from '../src/index'
import { HistoryModel } from '../src/model'
import { isMongooseLessThan7 } from '../src/version'
import { USER_DELETED } from './constants/events'
import server from './mongo/server'
import { type User, UserSchema } from './schemas/User'
vi.mock('../src/em', () => ({ default: { emit: vi.fn() } }))
describe('plugin - event delete & patch history disabled', () => {
const instance = server('plugin-event-deleted')
UserSchema.plugin(patchHistoryPlugin, {
eventDeleted: USER_DELETED,
patchHistoryDisabled: true,
})
const UserModel = model<User>('User', UserSchema)
beforeAll(async () => {
await instance.create()
})
afterAll(async () => {
await instance.destroy()
})
beforeEach(async () => {
await mongoose.connection.collection('users').deleteMany({})
await mongoose.connection.collection('history').deleteMany({})
})
afterEach(async () => {
vi.resetAllMocks()
})
it('should remove() and emit one delete event', async () => {
const john = await UserModel.create({ name: 'John', role: 'user' })
if (isMongooseLessThan7) {
// @ts-expect-error not available in Mongoose 6 and below
await john.remove()
} else {
await john.deleteOne()
}
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(1)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
// Check if data is deleted
const user = await UserModel.findById(john._id)
expect(user).toBeNull()
})
it('should remove() and emit two delete events', async () => {
const users = await UserModel.create([
{ name: 'John', role: 'user' },
{ name: 'Alice', role: 'user' },
{ name: 'Bob', role: 'admin' },
])
const [john, alice] = users
if (isMongooseLessThan7) {
// @ts-expect-error not available in Mongoose 6 and below
await UserModel.remove({ role: 'user' }).exec()
} else {
await UserModel.deleteMany({ role: 'user' }).exec()
}
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(2)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(alice.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const deletedAlice = await UserModel.findById(alice._id)
expect(deletedAlice).toBeNull()
const remaining = await UserModel.find({})
expect(remaining).toHaveLength(1)
})
it('should remove() and emit one delete event { single: true }', async () => {
const users = await UserModel.create([
{ name: 'John', role: 'user' },
{ name: 'Alice', role: 'user' },
{ name: 'Bob', role: 'admin' },
])
const [john] = users
if (isMongooseLessThan7) {
// @ts-expect-error not available in Mongoose 6 and below
await UserModel.remove({ role: 'user', name: 'John' }, { single: true }).exec()
} else {
await UserModel.deleteOne({ role: 'user', name: 'John' }).exec()
}
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(1)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const remaining = await UserModel.find({})
expect(remaining).toHaveLength(2)
})
it('should findOneAndDelete() and emit one delete event', async () => {
const users = await UserModel.create([
{ name: 'John', role: 'user' },
{ name: 'Alice', role: 'user' },
{ name: 'Bob', role: 'admin' },
])
const [john] = users
await UserModel.findOneAndDelete({ name: 'John' }).exec()
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(1)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const remaining = await UserModel.find({})
expect(remaining).toHaveLength(2)
})
it('should findOneAndRemove() and emit one delete event', async () => {
const users = await UserModel.create([
{ name: 'John', role: 'user' },
{ name: 'Alice', role: 'admin' },
{ name: 'Bob', role: 'admin' },
])
const [john] = users
if (isMongooseLessThan7) {
// @ts-expect-error not available in Mongoose 6 and below
await UserModel.findOneAndRemove({ role: 'user' }).exec()
} else {
await UserModel.findOneAndDelete({ role: 'user' }).exec()
}
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(1)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const remaining = await UserModel.find({ name: { $in: ['Alice', 'Bob'] } })
expect(remaining).toHaveLength(2)
})
it('should findByIdAndDelete() and emit one delete event', async () => {
const users = await UserModel.create([
{ name: 'John', role: 'user' },
{ name: 'Alice', role: 'user' },
{ name: 'Bob', role: 'admin' },
])
const [john] = users
await UserModel.findByIdAndDelete(john._id).exec()
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(1)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const remaining = await UserModel.find({ name: { $in: ['Alice', 'Bob'] } })
expect(remaining).toHaveLength(2)
})
it('should findByIdAndRemove() and emit one delete event', async () => {
const users = await UserModel.create([
{ name: 'John', role: 'user' },
{ name: 'Alice', role: 'user' },
{ name: 'Bob', role: 'admin' },
])
const [john] = users
if (isMongooseLessThan7) {
// @ts-expect-error not available in Mongoose 6 and below
await UserModel.findByIdAndRemove(john._id).exec()
} else {
await UserModel.findByIdAndDelete(john._id).exec()
}
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(1)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const remaining = await UserModel.find({ name: { $in: ['Alice', 'Bob'] } })
expect(remaining).toHaveLength(2)
})
it('should deleteOne() and emit one delete event', async () => {
const users = await UserModel.create([
{ name: 'John', role: 'user' },
{ name: 'Alice', role: 'admin' },
{ name: 'Bob', role: 'admin' },
])
const [john] = users
await UserModel.deleteOne({ role: 'user' }).exec()
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(1)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const remaining = await UserModel.find({ name: { $in: ['Alice', 'Bob'] } })
expect(remaining).toHaveLength(2)
})
it('should deleteMany() and emit two delete events', async () => {
const users = await UserModel.create([
{ name: 'John', role: 'user' },
{ name: 'Alice', role: 'user' },
{ name: 'Bob', role: 'admin' },
])
const [john, alice] = users
await UserModel.deleteMany({ role: 'user' }).exec()
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(2)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(alice.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const deletedAlice = await UserModel.findById(alice._id)
expect(deletedAlice).toBeNull()
const remaining = await UserModel.find({})
expect(remaining).toHaveLength(1)
})
it('should deleteMany() and emit one delete event { single: true }', async () => {
const users = await UserModel.create([
{ name: 'John', role: 'user' },
{ name: 'Alice', role: 'user' },
{ name: 'Bob', role: 'admin' },
])
const [john] = users
if (isMongooseLessThan7) {
await UserModel.deleteMany({ name: 'John' }, { single: true }).exec()
} else {
await UserModel.deleteOne({ name: 'John' }).exec()
}
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(1)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const remaining = await UserModel.find({})
expect(remaining).toHaveLength(2)
})
it('should create then delete and emit one delete event', async () => {
const john = await UserModel.create({ name: 'John', role: 'user' })
if (isMongooseLessThan7) {
// @ts-expect-error not available in Mongoose 6 and below
await john.delete()
} else {
await john.deleteOne()
}
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(1)
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
oldDoc: expect.objectContaining(john.toObject(toObjectOptions)),
})
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const remaining = await UserModel.find({})
expect(remaining).toHaveLength(0)
})
it('should ignoreHook option on deleteMany', async () => {
const john = await UserModel.create({ name: 'John', role: 'user' })
await UserModel.deleteMany({ role: 'user' }, { ignoreHook: true }).exec()
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(0)
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
})
it('should ignoreHook option on deleteOne', async () => {
const john = await UserModel.create({ name: 'John', role: 'user' })
await UserModel.deleteOne({ role: 'user' }, { ignoreHook: true }).exec()
const history = await HistoryModel.find({})
expect(history).toHaveLength(0)
expect(em.emit).toHaveBeenCalledTimes(0)
// Check if data is deleted
const deletedJohn = await UserModel.findById(john._id)
expect(deletedJohn).toBeNull()
const remaining = await UserModel.find({})
expect(remaining).toHaveLength(0)
})
})