import { mkdtemp, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import type { KtxCliIo } from '../src/cli-runtime.js'; import { runKtxSourceMapping } from '../src/source-mapping.js'; function makeIo() { let stdout = ''; let stderr = ''; return { io: { stdout: { write: (chunk: string) => { stdout += chunk; }, }, stderr: { write: (chunk: string) => { stderr += chunk; }, }, } satisfies KtxCliIo, stdout: () => stdout, stderr: () => stderr, }; } describe('source mapping commands', () => { let tempDir: string; beforeEach(async () => { tempDir = await mkdtemp(join(tmpdir(), 'ktx-source-mapping-')); }); afterEach(async () => { await rm(tempDir, { recursive: true, force: true }); }); async function writeConfig(metabaseMappings: string[]): Promise { await writeFile( join(tempDir, 'ktx.yaml'), [ 'connections:', ' warehouse:', ' driver: postgres', ' url: env:DATABASE_URL', ' metabase:', ' driver: metabase', ' api_url: https://metabase.example.com', ...metabaseMappings, '', ].join('\n'), 'utf-8', ); } it('fails Metabase validation when no sync-enabled target mapping exists', async () => { await writeConfig([]); const io = makeIo(); await expect( runKtxSourceMapping({ command: 'validate', projectDir: tempDir, connectionId: 'metabase' }, io.io), ).resolves.toBe(1); expect(io.stderr()).toContain('no sync-enabled mappings with a target connection for Metabase connection metabase'); }); it('passes Metabase validation when a sync-enabled target mapping exists', async () => { await writeConfig([ ' mappings:', ' databaseMappings:', ' "3": warehouse', ' syncEnabled:', ' "3": true', ]); const io = makeIo(); await expect( runKtxSourceMapping({ command: 'validate', projectDir: tempDir, connectionId: 'metabase' }, io.io), ).resolves.toBe(0); expect(io.stdout()).toContain('Mapping validation passed: metabase'); }); });