Works with frozen objects
Composition-based. Wraps your real objects instead of mutating them, so `Object.freeze`, sealed classes, and prototype-based code just work.
TypeScript-first test doubles for frozen objects, sealed classes, and any coding style β with matchers, spies, and first-class fake timers.


import { stub, match } from 'deride'
interface Database {
query(sql: string): Promise<unknown[]>
findById(id: number): Promise<unknown>
}
const mockDb = stub<Database>(['query', 'findById'])
mockDb.setup.query.toResolveWith([{ id: 1, name: 'alice' }])
mockDb.setup.findById.when(match.gte(100)).toRejectWith(new Error('not found'))
const result = await mockDb.query('SELECT * FROM users')
mockDb.expect.query.called.once()
mockDb.expect.query.called.withArg(match.regex(/FROM users/))
mockDb.expect.findById.called.never()No monkey-patching. mockDb is a wrapper around a fresh object. Your real Database class is untouched. That's why deride works on frozen objects, sealed classes, and any coding style.