1010
1111import { describe , expect , test , beforeAll , afterAll , mock } from "bun:test"
1212
13+ // Detect whether the native @altimateai/altimate-core napi binary is available.
14+ // CI environments don't have it, so Dispatcher-dependent describes must be skipped.
15+ let HAS_NATIVE = false
16+ try {
17+ require ( "@altimateai/altimate-core" )
18+ HAS_NATIVE = true
19+ } catch {
20+ HAS_NATIVE = false
21+ }
22+
1323// Mock DuckDB driver so sql.execute tests don't need native duckdb
1424mock . module ( "@altimateai/drivers/duckdb" , ( ) => ( {
1525 connect : async ( ) => ( {
@@ -27,19 +37,28 @@ mock.module("@altimateai/drivers/duckdb", () => ({
2737 } ) ,
2838} ) )
2939
30- import * as Dispatcher from "../../src/altimate/native/dispatcher"
31- import { registerAll } from "../../src/altimate/native/altimate-core"
32- import { registerAllSql } from "../../src/altimate/native/sql/register"
33- import { registerAll as registerConnections } from "../../src/altimate/native/connections/register"
34- import * as Registry from "../../src/altimate/native/connections/registry"
35- import { classifyAndCheck } from "../../src/altimate/tools/sql-classify"
36- import { SqlExecuteTool } from "../../src/altimate/tools/sql-execute"
40+ // Native-dependent imports are loaded dynamically to avoid crashing in CI
41+ // where the @altimateai /altimate-core napi binary is not available.
42+ let Dispatcher : typeof import ( "../../src/altimate/native/dispatcher" )
43+ let Registry : typeof import ( "../../src/altimate/native/connections/registry" )
44+ let classifyAndCheck : typeof import ( "../../src/altimate/tools/sql-classify" ) . classifyAndCheck
45+ let SqlExecuteTool : typeof import ( "../../src/altimate/tools/sql-execute" ) . SqlExecuteTool
3746import { Instance } from "../../src/project/instance"
3847import { SessionID , MessageID } from "../../src/session/schema"
3948import { tmpdir } from "../fixture/fixture"
4049
41- beforeAll ( ( ) => {
50+ beforeAll ( async ( ) => {
4251 process . env . ALTIMATE_TELEMETRY_DISABLED = "true"
52+ if ( ! HAS_NATIVE ) return
53+ Dispatcher = await import ( "../../src/altimate/native/dispatcher" )
54+ Registry = await import ( "../../src/altimate/native/connections/registry" )
55+ const sqlClassify = await import ( "../../src/altimate/tools/sql-classify" )
56+ classifyAndCheck = sqlClassify . classifyAndCheck
57+ const sqlExecute = await import ( "../../src/altimate/tools/sql-execute" )
58+ SqlExecuteTool = sqlExecute . SqlExecuteTool
59+ const { registerAll } = await import ( "../../src/altimate/native/altimate-core" )
60+ const { registerAllSql } = await import ( "../../src/altimate/native/sql/register" )
61+ const { registerAll : registerConnections } = await import ( "../../src/altimate/native/connections/register" )
4362 registerAll ( )
4463 registerAllSql ( )
4564 registerConnections ( )
@@ -64,7 +83,7 @@ const baseCtx = {
6483// 1. ADVERSARIAL: sql-classify bypass attempts
6584// ==========================================================================
6685
67- describe ( "Adversarial: sql-classify bypass attempts" , ( ) => {
86+ describe . skipIf ( ! HAS_NATIVE ) ( "Adversarial: sql-classify bypass attempts" , ( ) => {
6887 // --- SQL comment injection ---
6988
7089 test ( "line comment after SELECT hides nothing" , ( ) => {
@@ -295,7 +314,7 @@ describe("Adversarial: sql-classify bypass attempts", () => {
295314// 2. USER PERSPECTIVE: sql_execute tool with mocked permission flow
296315// ==========================================================================
297316
298- describe ( "User perspective: sql_execute permission flow" , ( ) => {
317+ describe . skipIf ( ! HAS_NATIVE ) ( "User perspective: sql_execute permission flow" , ( ) => {
299318 test ( "read query executes without asking permission" , async ( ) => {
300319 await using tmp = await tmpdir ( )
301320 await Instance . provide ( {
@@ -550,7 +569,7 @@ describe("User perspective: sql_execute permission flow", () => {
550569// 3. E2E: Full validation pipeline with realistic user scenarios
551570// ==========================================================================
552571
553- describe ( "E2E: realistic user scenarios through validation pipeline" , ( ) => {
572+ describe . skipIf ( ! HAS_NATIVE ) ( "E2E: realistic user scenarios through validation pipeline" , ( ) => {
554573 test ( "data analyst runs a safe reporting query" , async ( ) => {
555574 const sql = `
556575 SELECT
@@ -703,7 +722,7 @@ describe("E2E: realistic user scenarios through validation pipeline", () => {
703722// 4. E2E: Dispatcher error recovery and resilience
704723// ==========================================================================
705724
706- describe ( "E2E: error recovery and resilience" , ( ) => {
725+ describe . skipIf ( ! HAS_NATIVE ) ( "E2E: error recovery and resilience" , ( ) => {
707726 test ( "malformed SQL doesn't crash any pipeline stage" , async ( ) => {
708727 const malformedQueries = [
709728 "SELCT * FORM users" ,
@@ -792,7 +811,7 @@ describe("E2E: error recovery and resilience", () => {
792811// 5. Stress: concurrent and rapid-fire validation
793812// ==========================================================================
794813
795- describe ( "Stress: concurrent validation" , ( ) => {
814+ describe . skipIf ( ! HAS_NATIVE ) ( "Stress: concurrent validation" , ( ) => {
796815 test ( "20 concurrent validate calls all return results" , async ( ) => {
797816 const queries = Array . from (
798817 { length : 20 } ,
@@ -877,7 +896,7 @@ describe("Stress: concurrent validation", () => {
877896// 6. E2E: Dialect-specific queries through the full pipeline
878897// ==========================================================================
879898
880- describe ( "E2E: dialect-specific SQL through pipeline" , ( ) => {
899+ describe . skipIf ( ! HAS_NATIVE ) ( "E2E: dialect-specific SQL through pipeline" , ( ) => {
881900 test ( "Snowflake QUALIFY clause" , async ( ) => {
882901 const sql = `
883902 SELECT *
@@ -946,7 +965,7 @@ describe("E2E: dialect-specific SQL through pipeline", () => {
946965// 7. E2E: translate and optimize tools in the pipeline
947966// ==========================================================================
948967
949- describe ( "E2E: translate and optimize through pipeline" , ( ) => {
968+ describe . skipIf ( ! HAS_NATIVE ) ( "E2E: translate and optimize through pipeline" , ( ) => {
950969 test ( "sql.translate is callable and returns result shape" , async ( ) => {
951970 const r = await Dispatcher . call ( "sql.translate" , {
952971 sql : "SELECT IFNULL(name, 'unknown') FROM users" ,
0 commit comments