Skip to content

Instantly share code, notes, and snippets.

@Aschen
Created July 8, 2024 07:43
Show Gist options
  • Save Aschen/55eaf738c424d4339960b46416044cd1 to your computer and use it in GitHub Desktop.
Save Aschen/55eaf738c424d4339960b46416044cd1 to your computer and use it in GitHub Desktop.
VCR for methods
const YAML = require('yaml')
import Path from 'node:path'
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { createHash } from 'node:crypto'
export function vcr({
instance,
methods,
mode = 'cache',
verbose = true,
basePath = '.cache',
}: {
instance: any
methods: string[]
mode?: 'record' | 'playback' | 'cache'
verbose?: boolean
basePath?: string
}) {
for (const method of methods) {
if (typeof instance[method] !== 'function') {
throw new Error(`"${instance.name}.${method} is not a function`)
}
const originalMethod = instance[method].bind(instance)
const className = instance.constructor.name
const mockPath = Path.join(basePath, className)
mkdirSync(mockPath, { recursive: true })
verbose &&
console.info(
`Wrap method "${className}.${method}" with cache mode ${mode}`
)
instance[method] = async function (...args: any[]) {
const hash = createHash('sha256')
.update(JSON.stringify(args))
.digest('hex')
const filePath = Path.join(mockPath, `${hash}.yaml`)
const exists = existsSync(filePath)
if (!exists && mode === 'playback') {
throw new Error(`Cannot find cached result in playback mode`)
}
if (exists && mode === 'cache') {
verbose &&
console.info(`Get cache for "${className}.${method}" at ${filePath}`)
return YAML.parse(readFileSync(filePath, 'utf-8')).result
}
console.log('vcr before')
const result = await originalMethod(...args)
console.log('vcr after')
if (mode !== 'playback') {
console.info(`Set cache for "${className}.${method}" at ${filePath}`)
writeFileSync(
filePath,
YAML.stringify({
arguments: args,
result,
})
)
}
return result
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment