test: 492 tests, 78% line coverage
- Device domain: updateFromValues, organizeParameters, identifier - BaseModel: full CRUD mock tests - DeviceModel: all methods mocked - Other models: collectionName verification - MainStateMachine: start, handleResponse, state transitions - ConfigurationEvaluationState: init, GPN flow, GPN-unsupported skip - MongodbProvider: getMongoDb guard - device_utils: hash determinism - vitest.config.ts: coverage scope (excludes HTTP layer) - 492 tests passing, 78% line coverage
This commit is contained in:
1 parent
ab21f11b30
commit
12a1787151
10 files changed
+710
-3
No files matched your search
@@ -0,0 +1,128 @@
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
|
||||
const mockCollection = {
|
||||
find: vi.fn().mockReturnThis(),
|
||||
findOne: vi.fn(),
|
||||
insertOne: vi.fn(),
|
||||
insertMany: vi.fn(),
|
||||
updateOne: vi.fn(),
|
||||
updateMany: vi.fn(),
|
||||
deleteOne: vi.fn(),
|
||||
deleteMany: vi.fn(),
|
||||
countDocuments: vi.fn(),
|
||||
sort: vi.fn().mockReturnThis(),
|
||||
skip: vi.fn().mockReturnThis(),
|
||||
limit: vi.fn().mockReturnThis(),
|
||||
toArray: vi.fn(),
|
||||
}
|
||||
|
||||
const mockDb = { collection: vi.fn().mockReturnValue(mockCollection) }
|
||||
|
||||
vi.mock('#providers/mongodb_provider', () => ({
|
||||
getMongoDb: () => mockDb,
|
||||
}))
|
||||
|
||||
import { BaseModel } from '../../../database/base_model.js'
|
||||
|
||||
class TestModel extends BaseModel {
|
||||
static collectionName = 'test_collection'
|
||||
}
|
||||
|
||||
describe('BaseModel', () => {
|
||||
it('getDb returns the mocked db', () => {
|
||||
const db = TestModel.getDb()
|
||||
expect(db).toBe(mockDb)
|
||||
})
|
||||
|
||||
it('getCollection returns collection from db', () => {
|
||||
const col = TestModel.getCollection()
|
||||
expect(mockDb.collection).toHaveBeenCalledWith('test_collection')
|
||||
expect(col).toBe(mockCollection)
|
||||
})
|
||||
|
||||
it('find calls collection.find', async () => {
|
||||
mockCollection.toArray.mockResolvedValue([{ name: 'a' }])
|
||||
const results = await TestModel.find({ name: 'a' })
|
||||
expect(mockCollection.find).toHaveBeenCalledWith({ name: 'a' })
|
||||
expect(results).toEqual([{ name: 'a' }])
|
||||
})
|
||||
|
||||
it('findOne calls collection.findOne', async () => {
|
||||
mockCollection.findOne.mockResolvedValue({ x: 1 })
|
||||
const result = await TestModel.findOne({ x: 1 })
|
||||
expect(result).toEqual({ x: 1 })
|
||||
})
|
||||
|
||||
it('findById converts string to ObjectId', async () => {
|
||||
mockCollection.findOne.mockResolvedValue({ _id: 'abc' })
|
||||
await TestModel.findById('507f1f77bcf86cd799439011')
|
||||
expect(mockCollection.findOne).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('create inserts with timestamps', async () => {
|
||||
mockCollection.insertOne.mockResolvedValue({ insertedId: 'new-id' })
|
||||
const result = await TestModel.create({ name: 'test' })
|
||||
expect(result.name).toBe('test')
|
||||
expect(result.createdAt).toBeDefined()
|
||||
expect(result.updatedAt).toBeDefined()
|
||||
expect(result._id).toBe('new-id')
|
||||
})
|
||||
|
||||
it('createMany inserts multiple docs', async () => {
|
||||
mockCollection.insertMany.mockResolvedValue({ insertedIds: { 0: 'id1', 1: 'id2' } })
|
||||
const results = await TestModel.createMany([{ a: 1 }, { a: 2 }])
|
||||
expect(results).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('updateOne with $set passes through', async () => {
|
||||
mockCollection.updateOne.mockResolvedValue({ modifiedCount: 1 })
|
||||
await TestModel.updateOne({ name: 'x' }, { $set: { val: 2 } })
|
||||
expect(mockCollection.updateOne).toHaveBeenCalledWith({ name: 'x' }, { $set: { val: 2 } })
|
||||
})
|
||||
|
||||
it('updateOne without $set wraps in $set', async () => {
|
||||
mockCollection.updateOne.mockResolvedValue({ modifiedCount: 1 })
|
||||
await TestModel.updateOne({ name: 'x' }, { val: 3 })
|
||||
expect(mockCollection.updateOne).toHaveBeenCalledWith(
|
||||
{ name: 'x' },
|
||||
expect.objectContaining({ $set: expect.objectContaining({ val: 3 }) })
|
||||
)
|
||||
})
|
||||
|
||||
it('updateMany works', async () => {
|
||||
mockCollection.updateMany.mockResolvedValue({ modifiedCount: 5 })
|
||||
await TestModel.updateMany({ type: 'a' }, { $set: { active: false } })
|
||||
expect(mockCollection.updateMany).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('deleteOne returns boolean', async () => {
|
||||
mockCollection.deleteOne.mockResolvedValue({ deletedCount: 1 })
|
||||
const result = await TestModel.deleteOne({ name: 'x' })
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
|
||||
it('deleteOne returns false when not found', async () => {
|
||||
mockCollection.deleteOne.mockResolvedValue({ deletedCount: 0 })
|
||||
const result = await TestModel.deleteOne({ name: 'nonexistent' })
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it('deleteMany returns count', async () => {
|
||||
mockCollection.deleteMany.mockResolvedValue({ deletedCount: 3 })
|
||||
const count = await TestModel.deleteMany({ old: true })
|
||||
expect(count).toBe(3)
|
||||
})
|
||||
|
||||
it('paginate returns paginated data', async () => {
|
||||
mockCollection.countDocuments.mockResolvedValue(50)
|
||||
mockCollection.toArray.mockResolvedValue([{ id: 1 }, { id: 2 }])
|
||||
const result = await TestModel.paginate(2, 10, {})
|
||||
expect(result.total).toBe(50)
|
||||
expect(result.page).toBe(2)
|
||||
expect(result.perPage).toBe(10)
|
||||
expect(result.lastPage).toBe(5)
|
||||
expect(result.data).toHaveLength(2)
|
||||
expect(mockCollection.skip).toHaveBeenCalledWith(10) // (2-1) * 10
|
||||
expect(mockCollection.limit).toHaveBeenCalledWith(10)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user