Skip to main content
Glama

Prisma MCP Server

Official
by prisma
Apache 2.0
4
44,192
  • Linux
  • Apple
vitestContext.ts8.18 kB
import path from 'node:path' import { type ExecaChildProcess, execaNode } from 'execa' import fs from 'fs-jetpack' import type { FSJetpack, InspectTreeResult } from 'fs-jetpack/types' import tempy from 'tempy' import { afterEach, beforeEach, type MockInstance, vi } from 'vitest' /** * Base test context. */ export type BaseContext = { tmpDir: string fs: FSJetpack mocked: { cwd: string } /** * Set up the temporary directory based on the contents of some fixture. */ fixture: (name: string) => void /** * Spawn the Prisma cli using the temporary directory as the CWD. * * @remarks * * For this to work the source must be built */ cli: (...input: string[]) => ExecaChildProcess<string> printDir(dir: string, extensions: string[]): void /** * JavaScript-friendly implementation of the `tree` command. It skips the `node_modules` directory. * @param itemPath The path to start the tree from, defaults to the root of the temporary directory * @param indent How much to indent each level of the tree, defaults to '' * @returns String representation of the directory tree */ tree: (itemPath?: string, indent?: string) => void } /** * Create test context to use in tests. Provides the following: * * - A temporary directory * - an fs-jetpack instance bound to the temporary directory * - Mocked process.cwd via Node process.chdir * - Fixture loader for bootstrapping the temporary directory with content */ export const vitestContext = { new: function (ctx: BaseContext = {} as any) { const c = ctx as BaseContext beforeEach(() => { const originalCwd = process.cwd() c.mocked = c.mocked ?? { cwd: process.cwd(), } c.tmpDir = tempy.directory() c.fs = fs.cwd(c.tmpDir) c.tree = (startFrom = c.tmpDir, indent = '') => { function* generateDirectoryTree(children: InspectTreeResult[], indent = ''): Generator<String> { for (const child of children) { if (child.name === 'node_modules' || child.name === '.git') { continue } if (child.type === 'dir') { yield `${indent}└── ${child.name}/` yield* generateDirectoryTree(child.children, indent + ' ') } else if (child.type === 'symlink') { yield `${indent} -> ${child.relativePath}` } else { yield `${indent}└── ${child.name}` } } } const children = c.fs.inspectTree(startFrom, { relativePath: true, symlinks: 'report' })?.children || [] return ` ${[...generateDirectoryTree(children, indent)].join('\n')} ` } c.fixture = (name: string) => { // copy the specific fixture directory in isolated tmp directory c.fs.copy(path.join(originalCwd, 'src', '__tests__', 'fixtures', name), '.', { overwrite: true, }) // symlink to local client version in tmp dir c.fs.symlink(path.join(originalCwd, '..', 'client'), path.join(c.fs.cwd(), 'node_modules', '@prisma', 'client')) } c.cli = (...input) => { return execaNode(path.join(originalCwd, '../cli/build/index.js'), input, { cwd: c.fs.cwd(), stdio: 'pipe', all: true, }) } c.printDir = (dir, extensions) => { const content = c.fs.list(dir) ?? [] content.sort((a, b) => a.localeCompare(b)) return content .filter((name) => extensions.includes(path.extname(name))) .map((name) => `${name}:\n\n${c.fs.read(path.join(dir, name))}`) .join('\n\n') } process.chdir(c.tmpDir) }) afterEach(() => { process.chdir(c.mocked.cwd) }) return factory(ctx) }, } /** * A function that provides additional test context. */ type ContextContributor<Context, NewContext> = (ctx: Context) => Context & NewContext /** * Main context builder API that permits recursively building up context. */ function factory<Context>(ctx: Context) { return { add<NewContext>(contextContributor: ContextContributor<Context, NewContext>) { const newCtx = contextContributor(ctx) return factory<Context & NewContext>(newCtx) }, assemble(): Context { return ctx }, } } /** * Test context contributor. Mocks console.error with a Vitest spy before each test. */ type ConsoleContext = { mocked: { 'console.error': MockInstance<typeof console.error> 'console.log': MockInstance<typeof console.log> 'console.info': MockInstance<typeof console.info> 'console.warn': MockInstance<typeof console.warn> } } export const vitestConsoleContext = <Ctx extends BaseContext>() => (c: Ctx) => { const ctx = c as Ctx & ConsoleContext beforeEach(() => { ctx.mocked['console.error'] = vi.spyOn(console, 'error').mockImplementation(() => {}) ctx.mocked['console.log'] = vi.spyOn(console, 'log').mockImplementation(() => {}) ctx.mocked['console.info'] = vi.spyOn(console, 'info').mockImplementation(() => {}) ctx.mocked['console.warn'] = vi.spyOn(console, 'warn').mockImplementation(() => {}) }) afterEach(() => { ctx.mocked['console.error'].mockRestore() ctx.mocked['console.log'].mockRestore() ctx.mocked['console.info'].mockRestore() ctx.mocked['console.warn'].mockRestore() }) return ctx } /** * Test context contributor. Mocks process.std(out|err).write with a Vitest spy before each test. */ type ProcessContext = { mocked: { 'process.stderr.write': MockInstance<typeof process.stderr.write> 'process.stdout.write': MockInstance<typeof process.stdout.write> } normalizedCapturedStdout: () => string normalizedCapturedStderr: () => string clearCapturedStdout: () => void clearCapturedStderr: () => void } type NormalizationRule = [RegExp | string, string] export type ProcessContextSettings = { normalizationRules: NormalizationRule[] } export const vitestStdoutContext = <Ctx extends BaseContext>({ normalizationRules }: ProcessContextSettings = { normalizationRules: [] }) => (c: Ctx) => { const ctx = c as Ctx & ProcessContext const normalize = (text: string, rules: NormalizationRule[]) => { for (const [pattern, replacement] of rules) { text = text.replace(pattern, replacement) } return text } beforeEach(() => { ctx.mocked['process.stderr.write'] = vi.spyOn(process.stderr, 'write').mockImplementation(() => true) ctx.mocked['process.stdout.write'] = vi.spyOn(process.stdout, 'write').mockImplementation(() => true) ctx.normalizedCapturedStdout = () => normalize( ctx.mocked['process.stdout.write'].mock.calls.map((call) => call[0] as string).join(''), normalizationRules, ) ctx.normalizedCapturedStderr = () => normalize( ctx.mocked['process.stderr.write'].mock.calls.map((call) => call[0] as string).join(''), normalizationRules, ) ctx.clearCapturedStdout = () => ctx.mocked['process.stdout.write'].mockClear() ctx.clearCapturedStderr = () => ctx.mocked['process.stderr.write'].mockClear() }) afterEach(() => { ctx.mocked['process.stderr.write'].mockRestore() ctx.mocked['process.stdout.write'].mockRestore() }) return ctx } /** * Test context contributor. Mocks process.exit with a spy and records the exit code. */ type ProcessExitContext = { mocked: { 'process.exit': MockInstance<typeof process.exit> } recordedExitCode: () => number } export const vitestProcessExitContext = <C extends BaseContext>() => (c: C) => { const ctx = c as C & ProcessExitContext beforeEach(() => { ctx.mocked['process.exit'] = vi.spyOn(process, 'exit').mockImplementation((number) => { throw new Error('process.exit: ' + number) }) ctx.recordedExitCode = () => ctx.mocked['process.exit'].mock.calls[0]?.[0] ?? 0 }) afterEach(() => { ctx.mocked['process.exit'].mockRestore() }) return ctx } export const processExitContext = vitestProcessExitContext

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/prisma/prisma'

If you have feedback or need assistance with the MCP directory API, please join our Discord server