From 5f61995296e7208c6b5a1b5deace1db117727d8a Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Fri, 18 Jul 2025 10:48:49 -0600 Subject: [PATCH] Fix linting errors --- apps/server/src/api/v2/dictionaries/index.ts | 3 +- .../api/v2/slack/services/slack-helpers.ts | 35 ++-- .../services/slack-oauth-service.test.ts | 3 +- .../v2/slack/services/slack-oauth-service.ts | 10 +- apps/server/src/middleware/logger.test.ts | 2 - .../slack-agent-task/slack-agent-task.ts | 10 +- biome.json | 6 +- .../src/access-controls.int.test.ts | 42 ++--- .../src/chats-cached.int.test.ts | 12 +- .../access-controls/src/chats.int.test.ts | 9 +- .../analyst-agent/analyst-agent.int.test.ts | 2 +- .../think-and-prep-agent.int.test.ts | 2 +- .../analyst-step-failed-tool-handling.test.ts | 2 +- .../steps/analyst-step-file-selection.test.ts | 2 +- .../steps/create-todos-step-reasoning.test.ts | 2 +- .../steps/extract-values-search-step.test.ts | 2 +- .../steps/think-and-prep-todos.int.test.ts | 2 +- .../done-tool-streaming.test.ts | 2 +- .../message-user-clarifying-question.test.ts | 9 +- .../message-user-clarifying-question.ts | 8 +- ...respond-without-analysis-streaming.test.ts | 2 +- .../execute-sql-streaming.test.ts | 2 +- .../database-tools/sql-limit-helper.test.ts | 5 +- ...sequential-thinking-tool-streaming.test.ts | 2 +- .../create-dashboards-file-tool.int.test.ts | 2 +- ...create-metrics-file-tool-streaming.test.ts | 2 +- .../create-metrics-file-tool.int.test.ts | 2 +- .../version-history-helpers.test.ts | 6 +- .../chunk-processor-deferred-response.test.ts | 48 ++++- ...unk-processor-escape-normalization.test.ts | 9 +- .../chunk-processor-failure-handling.test.ts | 2 +- .../database/chunk-processor-sql.test.ts | 4 +- .../utils/database/chunk-processor.test.ts | 27 ++- .../ai/src/utils/database/chunk-processor.ts | 11 +- .../format-llm-messages-as-reasoning.ts | 9 +- packages/ai/src/utils/database/types.ts | 7 +- packages/ai/src/utils/file-selection.test.ts | 10 +- packages/ai/src/utils/file-selection.ts | 8 +- .../src/utils/memory/ai-sdk-bundling.test.ts | 2 +- .../message-converters-error-handling.test.ts | 5 +- .../utils/memory/message-converters.test.ts | 34 ++-- .../ai/src/utils/memory/message-converters.ts | 16 +- .../src/utils/memory/message-history.test.ts | 2 +- .../memory/stored-values-to-messages.test.ts | 6 +- .../utils/memory/todos-to-messages.test.ts | 5 +- .../memory/workflow-message-flow.test.ts | 2 +- .../ai/src/utils/retry/retry-helpers.test.ts | 4 +- .../optimistic-json-parser-edge-cases.test.ts | 5 +- .../optimistic-json-parser-stress.test.ts | 5 +- .../streaming/optimistic-json-parser.test.ts | 5 +- .../workflows/analyst-workflow.int.test.ts | 23 ++- .../workflows/message-bundling-debug.test.ts | 12 +- .../workflow-message-accumulation.test.ts | 9 +- .../data-source/src/adapters/base.test.ts | 8 +- .../src/adapters/bigquery.int.test.ts | 4 +- .../data-source/src/adapters/bigquery.test.ts | 14 +- .../data-source/src/adapters/factory.test.ts | 6 +- .../src/adapters/max-rows-limiting.test.ts | 8 +- .../src/adapters/mysql.int.test.ts | 4 +- .../data-source/src/adapters/mysql.test.ts | 32 ++-- .../src/adapters/postgresql.int.test.ts | 4 +- .../src/adapters/postgresql.test.ts | 22 +-- .../src/adapters/redshift.int.test.ts | 4 +- .../data-source/src/adapters/redshift.test.ts | 30 ++- .../snowflake-memory-protection.int.test.ts | 3 +- .../src/adapters/snowflake.int.test.ts | 4 +- .../src/adapters/snowflake.test.ts | 176 ++++++++++++------ .../src/adapters/sqlserver.int.test.ts | 4 +- .../src/adapters/sqlserver.test.ts | 59 +++--- .../data-source/src/adapters/timeout.test.ts | 24 +-- packages/data-source/src/config/timeouts.ts | 2 +- .../data-source/src/data-source.int.test.ts | 16 +- .../src/introspection/bigquery.int.test.ts | 2 +- .../multi-datasource.int.test.ts | 2 +- .../src/introspection/mysql.int.test.ts | 2 +- .../src/introspection/postgresql.int.test.ts | 2 +- .../src/introspection/redshift.int.test.ts | 2 +- .../src/introspection/snowflake.int.test.ts | 2 +- .../src/introspection/sqlserver.int.test.ts | 2 +- .../src/chats/chat.types.test.ts | 2 +- .../dataSources/createTestDataSource.test.ts | 24 ++- .../src/database/messageUpdates.test.ts | 32 ++-- .../messages/createTestMessage.test.ts | 9 +- .../createTestMessageWithContext.test.ts | 2 +- .../database/messages/messageContext.test.ts | 14 +- .../src/database/updateMessageFields.test.ts | 22 ++- .../src/envHelpers/env-helpers.test.ts | 97 +++++----- .../test-utils/src/envHelpers/env-helpers.ts | 4 +- packages/test-utils/src/mock-helpers.test.ts | 52 +++--- packages/test-utils/src/mock-helpers.ts | 2 +- 90 files changed, 654 insertions(+), 502 deletions(-) diff --git a/apps/server/src/api/v2/dictionaries/index.ts b/apps/server/src/api/v2/dictionaries/index.ts index 0b0522415..61918be12 100644 --- a/apps/server/src/api/v2/dictionaries/index.ts +++ b/apps/server/src/api/v2/dictionaries/index.ts @@ -5,6 +5,7 @@ import currencyRoutes from './currency'; const app = new Hono(); -export default app.use('*', requireAuth) +export default app + .use('*', requireAuth) .route('/color-themes', colorThemesRoutes) .route('/currency', currencyRoutes); diff --git a/apps/server/src/api/v2/slack/services/slack-helpers.ts b/apps/server/src/api/v2/slack/services/slack-helpers.ts index fbe7ccadc..df7d1e9db 100644 --- a/apps/server/src/api/v2/slack/services/slack-helpers.ts +++ b/apps/server/src/api/v2/slack/services/slack-helpers.ts @@ -194,8 +194,10 @@ export async function updateIntegrationAfterOAuth( ): Promise { try { const currentIntegration = await getIntegrationById(integrationId); - const isReinstallation = (currentIntegration?.oauthMetadata as Record)?.isReinstallation; - const originalSettings = (currentIntegration?.oauthMetadata as Record)?.originalSettings as OriginalSettings; + const isReinstallation = (currentIntegration?.oauthMetadata as Record) + ?.isReinstallation; + const originalSettings = (currentIntegration?.oauthMetadata as Record) + ?.originalSettings as OriginalSettings; const baseUpdateData = { ...params, @@ -207,17 +209,18 @@ export async function updateIntegrationAfterOAuth( updatedAt: new Date().toISOString(), }; - const updateData = isReinstallation && originalSettings - ? { - ...baseUpdateData, - ...(originalSettings.defaultChannel !== undefined && { - defaultChannel: originalSettings.defaultChannel, - }), - ...(originalSettings.defaultSharingPermissions !== undefined && { - defaultSharingPermissions: originalSettings.defaultSharingPermissions, - }), - } - : baseUpdateData; + const updateData = + isReinstallation && originalSettings + ? { + ...baseUpdateData, + ...(originalSettings.defaultChannel !== undefined && { + defaultChannel: originalSettings.defaultChannel, + }), + ...(originalSettings.defaultSharingPermissions !== undefined && { + defaultSharingPermissions: originalSettings.defaultSharingPermissions, + }), + } + : baseUpdateData; await db .update(slackIntegrations) @@ -249,8 +252,10 @@ export async function markIntegrationAsFailed( return; } - const isReinstallation = (integration.oauthMetadata as Record)?.isReinstallation; - const originalSettings = (integration.oauthMetadata as Record)?.originalSettings as OriginalSettings; + const isReinstallation = (integration.oauthMetadata as Record) + ?.isReinstallation; + const originalSettings = (integration.oauthMetadata as Record) + ?.originalSettings as OriginalSettings; if (integration.status === 'pending') { if (isReinstallation && originalSettings) { diff --git a/apps/server/src/api/v2/slack/services/slack-oauth-service.test.ts b/apps/server/src/api/v2/slack/services/slack-oauth-service.test.ts index 56085d378..16098a264 100644 --- a/apps/server/src/api/v2/slack/services/slack-oauth-service.test.ts +++ b/apps/server/src/api/v2/slack/services/slack-oauth-service.test.ts @@ -66,7 +66,8 @@ describe('SlackOAuthService', () => { id: 'existing-integration', organizationId: 'org-123', status: 'active', - scope: 'app_mentions:read,channels:history,channels:join,channels:manage,channels:read,chat:write,chat:write.public,commands,files:read,files:write,groups:history,groups:write,im:history,im:read,im:write,mpim:history,mpim:read,mpim:write,reactions:write,reactions:read,users:read,users:read.email', + scope: + 'app_mentions:read,channels:history,channels:join,channels:manage,channels:read,chat:write,chat:write.public,commands,files:read,files:write,groups:history,groups:write,im:history,im:read,im:write,mpim:history,mpim:read,mpim:write,reactions:write,reactions:read,users:read,users:read.email', } as any); await expect( diff --git a/apps/server/src/api/v2/slack/services/slack-oauth-service.ts b/apps/server/src/api/v2/slack/services/slack-oauth-service.ts index 88a367c2c..6b44cdda7 100644 --- a/apps/server/src/api/v2/slack/services/slack-oauth-service.ts +++ b/apps/server/src/api/v2/slack/services/slack-oauth-service.ts @@ -9,11 +9,11 @@ import { oauthStateStorage, tokenStorage } from './token-storage'; */ function validateScopes(currentScopeString?: string | null): boolean { if (!currentScopeString) return false; - - const currentScopes = currentScopeString.includes(',') - ? currentScopeString.split(',').map(s => s.trim()) - : currentScopeString.split(' ').map(s => s.trim()); - + + const currentScopes = currentScopeString.includes(',') + ? currentScopeString.split(',').map((s) => s.trim()) + : currentScopeString.split(' ').map((s) => s.trim()); + const requiredScopes = [...SLACK_OAUTH_SCOPES]; return requiredScopes.every((scope) => currentScopes.includes(scope)); } diff --git a/apps/server/src/middleware/logger.test.ts b/apps/server/src/middleware/logger.test.ts index 81d26183c..e2b710de9 100644 --- a/apps/server/src/middleware/logger.test.ts +++ b/apps/server/src/middleware/logger.test.ts @@ -34,7 +34,6 @@ describe('logger middleware', () => { }); it('should use info level by default when LOG_LEVEL is not set', async () => { - // biome-ignore lint/performance/noDelete: delete process.env.LOG_LEVEL; const { loggerMiddleware } = await import('./logger'); @@ -83,7 +82,6 @@ describe('logger middleware', () => { }); it('should not capture console methods when LOG_LEVEL is not set', async () => { - // biome-ignore lint/performance/noDelete: delete process.env.LOG_LEVEL; // Create mocks diff --git a/apps/trigger/src/tasks/slack-agent-task/slack-agent-task.ts b/apps/trigger/src/tasks/slack-agent-task/slack-agent-task.ts index 7d03cf2aa..673b08896 100644 --- a/apps/trigger/src/tasks/slack-agent-task/slack-agent-task.ts +++ b/apps/trigger/src/tasks/slack-agent-task/slack-agent-task.ts @@ -2,10 +2,10 @@ import { chats, db, eq, messages } from '@buster/database'; import { SlackMessagingService, addReaction, + convertMarkdownToSlack, getReactions, getThreadMessages, removeReaction, - convertMarkdownToSlack, } from '@buster/slack'; import { type TaskOutput, logger, runs, schemaTask, wait } from '@trigger.dev/sdk'; import { z } from 'zod'; @@ -549,10 +549,10 @@ export const slackAgentTask: ReturnType< // Convert markdown to Slack format const convertedResponse = convertMarkdownToSlack(responseText); - + // Create the message with converted text and any blocks from conversion const messageBlocks = [...(convertedResponse.blocks || [])]; - + // If no blocks were created from conversion, create a section block with the converted text if (messageBlocks.length === 0 && convertedResponse.text) { messageBlocks.push({ @@ -563,7 +563,7 @@ export const slackAgentTask: ReturnType< }, }); } - + // Add the action button block messageBlocks.push({ type: 'actions' as const, @@ -579,7 +579,7 @@ export const slackAgentTask: ReturnType< }, ], }); - + const completionMessage = { text: convertedResponse.text || responseText, // Use converted text as fallback thread_ts: chatDetails.slackThreadTs, diff --git a/biome.json b/biome.json index 625efbf3c..91556e2e2 100644 --- a/biome.json +++ b/biome.json @@ -23,7 +23,8 @@ "noConsoleLog": "warn" }, "complexity": { - "noExcessiveCognitiveComplexity": "off" + "noExcessiveCognitiveComplexity": "off", + "noForEach": "off" }, "performance": { "noDelete": "error" @@ -128,6 +129,9 @@ "suspicious": { "noConsoleLog": "off", "noExplicitAny": "off" + }, + "performance": { + "noDelete": "off" } } } diff --git a/packages/access-controls/src/access-controls.int.test.ts b/packages/access-controls/src/access-controls.int.test.ts index b2966af7c..83deeb6f4 100644 --- a/packages/access-controls/src/access-controls.int.test.ts +++ b/packages/access-controls/src/access-controls.int.test.ts @@ -500,7 +500,7 @@ describe('Access Controls Integration Tests - Organization Default Permission Gr describe('getPermissionedDatasets Integration Tests', () => { const db = getDb(); - + // Generate unique IDs for our test users const testUserId = 'c2dd64cd-f7f3-4884-bc91-d46ae431901e'; const noAccessUserId = uuidv4(); @@ -514,7 +514,7 @@ describe('getPermissionedDatasets Integration Tests', () => { beforeAll(async () => { const now = new Date().toISOString(); - + // Create test organization await db.insert(organizations).values({ id: testOrgIdForUsers, @@ -653,29 +653,27 @@ describe('getPermissionedDatasets Integration Tests', () => { afterAll(async () => { // Clean up test data - await db.delete(datasetsToPermissionGroups) + await db + .delete(datasetsToPermissionGroups) .where(eq(datasetsToPermissionGroups.permissionGroupId, limitedPermissionGroupId)); - - await db.delete(permissionGroupsToIdentities) + + await db + .delete(permissionGroupsToIdentities) .where(eq(permissionGroupsToIdentities.permissionGroupId, limitedPermissionGroupId)); - - await db.delete(permissionGroups) - .where(eq(permissionGroups.id, limitedPermissionGroupId)); - - await db.delete(datasets) - .where(eq(datasets.organizationId, testOrgIdForUsers)); - - await db.delete(dataSources) - .where(eq(dataSources.id, testDataSourceIdForUsers)); - - await db.delete(usersToOrganizations) + + await db.delete(permissionGroups).where(eq(permissionGroups.id, limitedPermissionGroupId)); + + await db.delete(datasets).where(eq(datasets.organizationId, testOrgIdForUsers)); + + await db.delete(dataSources).where(eq(dataSources.id, testDataSourceIdForUsers)); + + await db + .delete(usersToOrganizations) .where(eq(usersToOrganizations.organizationId, testOrgIdForUsers)); - - await db.delete(users) - .where(inArray(users.id, [noAccessUserId, limitedAccessUserId])); - - await db.delete(organizations) - .where(eq(organizations.id, testOrgIdForUsers)); + + await db.delete(users).where(inArray(users.id, [noAccessUserId, limitedAccessUserId])); + + await db.delete(organizations).where(eq(organizations.id, testOrgIdForUsers)); }); describe('User Dataset Access - Full Access User', () => { diff --git a/packages/access-controls/src/chats-cached.int.test.ts b/packages/access-controls/src/chats-cached.int.test.ts index a7837ad4c..8ac5e023a 100644 --- a/packages/access-controls/src/chats-cached.int.test.ts +++ b/packages/access-controls/src/chats-cached.int.test.ts @@ -147,15 +147,15 @@ describe('canUserAccessChatCached Integration Tests', () => { // Wait for cache to expire (30 seconds + buffer) // Note: In a real test environment, we'd want a shorter TTL // For now, we'll just verify the cache works within the TTL - await new Promise(resolve => setTimeout(resolve, 100)); - + await new Promise((resolve) => setTimeout(resolve, 100)); + // Should still be cached await canUserAccessChatCached({ userId, chatId }); expect(spiedCanUserAccessChat).toHaveBeenCalledTimes(1); // Clear the specific cache entry to simulate expiration invalidateAccess(userId, chatId); - + // Next call should hit the database again await canUserAccessChatCached({ userId, chatId }); expect(spiedCanUserAccessChat).toHaveBeenCalledTimes(2); @@ -181,15 +181,15 @@ describe('canUserAccessChatCached Integration Tests', () => { expect(spiedCanUserAccessChat).toHaveBeenCalledTimes(1); // Still only 1 DB call // Wait a bit to simulate time passing - await new Promise(resolve => setTimeout(resolve, 100)); - + await new Promise((resolve) => setTimeout(resolve, 100)); + // Should still be cached (TTL is refreshed on each access) await canUserAccessChatCached({ userId, chatId }); expect(spiedCanUserAccessChat).toHaveBeenCalledTimes(1); // Manually invalidate the cache entry to verify refresh behavior invalidateAccess(userId, chatId); - + // Next call should hit the database again await canUserAccessChatCached({ userId, chatId }); expect(spiedCanUserAccessChat).toHaveBeenCalledTimes(2); diff --git a/packages/access-controls/src/chats.int.test.ts b/packages/access-controls/src/chats.int.test.ts index c00948ba2..1cf325c50 100644 --- a/packages/access-controls/src/chats.int.test.ts +++ b/packages/access-controls/src/chats.int.test.ts @@ -223,11 +223,14 @@ describe('canUserAccessChat Integration Tests', () => { await db.delete(chats).where(eq(chats.organizationId, testOrgId)); // Delete users_to_organizations - these reference users - await db.delete(usersToOrganizations).where(eq(usersToOrganizations.organizationId, testOrgId)); + await db + .delete(usersToOrganizations) + .where(eq(usersToOrganizations.organizationId, testOrgId)); // Update any remaining references to set createdBy/updatedBy to null before deleting users // This handles any references we might have missed - await db.update(usersToOrganizations) + await db + .update(usersToOrganizations) .set({ createdBy: null, updatedBy: null }) .where( and( @@ -235,7 +238,7 @@ describe('canUserAccessChat Integration Tests', () => { isNull(usersToOrganizations.deletedAt) ) ); - + // Now we can safely delete users await db.delete(users).where(eq(users.id, testUserId)); await db.delete(users).where(eq(users.id, testAdminUserId)); diff --git a/packages/ai/src/agents/analyst-agent/analyst-agent.int.test.ts b/packages/ai/src/agents/analyst-agent/analyst-agent.int.test.ts index a3118e0a5..f30c85719 100644 --- a/packages/ai/src/agents/analyst-agent/analyst-agent.int.test.ts +++ b/packages/ai/src/agents/analyst-agent/analyst-agent.int.test.ts @@ -2,8 +2,8 @@ import { RuntimeContext } from '@mastra/core/runtime-context'; import type { CoreMessage } from 'ai'; import { initLogger, wrapTraced } from 'braintrust'; import { afterAll, beforeAll, describe, expect, test } from 'vitest'; -import { analystAgent } from './analyst-agent'; import type { AnalystRuntimeContext } from '../../workflows/analyst-workflow'; +import { analystAgent } from './analyst-agent'; describe('Analyst Agent Integration Tests', () => { beforeAll(async () => { diff --git a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.int.test.ts b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.int.test.ts index d83e88cda..dfe3014cf 100644 --- a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.int.test.ts +++ b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.int.test.ts @@ -2,8 +2,8 @@ import { RuntimeContext } from '@mastra/core/runtime-context'; import type { CoreMessage } from 'ai'; import { initLogger, wrapTraced } from 'braintrust'; import { afterAll, beforeAll, describe, expect, test } from 'vitest'; -import { thinkAndPrepAgent } from './think-and-prep-agent'; import type { AnalystRuntimeContext } from '../../workflows/analyst-workflow'; +import { thinkAndPrepAgent } from './think-and-prep-agent'; describe('Think and Prep Agent Integration Tests', () => { beforeAll(async () => { diff --git a/packages/ai/src/steps/analyst-step-failed-tool-handling.test.ts b/packages/ai/src/steps/analyst-step-failed-tool-handling.test.ts index b5326002c..dcfe39e9f 100644 --- a/packages/ai/src/steps/analyst-step-failed-tool-handling.test.ts +++ b/packages/ai/src/steps/analyst-step-failed-tool-handling.test.ts @@ -1,10 +1,10 @@ -import { describe, expect, test } from 'vitest'; import type { ChatMessageReasoningMessage, ChatMessageReasoningMessage_File, ChatMessageReasoningMessage_Files, ChatMessageResponseMessage, } from '@buster/server-shared/chats'; +import { describe, expect, test } from 'vitest'; import { hasFailureIndicators, hasFileFailureIndicators } from '../utils/database/types'; // Import the functions we want to test diff --git a/packages/ai/src/steps/analyst-step-file-selection.test.ts b/packages/ai/src/steps/analyst-step-file-selection.test.ts index 11058c1b8..99ca65fa4 100644 --- a/packages/ai/src/steps/analyst-step-file-selection.test.ts +++ b/packages/ai/src/steps/analyst-step-file-selection.test.ts @@ -1,8 +1,8 @@ -import { describe, expect, test } from 'vitest'; import type { ChatMessageReasoningMessage, ChatMessageResponseMessage, } from '@buster/server-shared/chats'; +import { describe, expect, test } from 'vitest'; import { hasFailureIndicators, hasFileFailureIndicators } from '../utils/database/types'; // Import the functions we want to test (we'll need to export them from analyst-step.ts) diff --git a/packages/ai/src/steps/create-todos-step-reasoning.test.ts b/packages/ai/src/steps/create-todos-step-reasoning.test.ts index 416da37f1..87a1f75d3 100644 --- a/packages/ai/src/steps/create-todos-step-reasoning.test.ts +++ b/packages/ai/src/steps/create-todos-step-reasoning.test.ts @@ -1,9 +1,9 @@ import { createTestChat, createTestMessage, withTestEnv } from '@buster/test-utils'; import { RuntimeContext } from '@mastra/core/runtime-context'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; +import type { AnalystRuntimeContext } from '../workflows/analyst-workflow'; import { createTodosStep } from './create-todos-step'; import { getRawLlmMessagesByMessageId } from './get-chat-history'; -import type { AnalystRuntimeContext } from '../workflows/analyst-workflow'; describe('Create Todos Step - Reasoning Integration', () => { beforeAll(async () => { diff --git a/packages/ai/src/steps/extract-values-search-step.test.ts b/packages/ai/src/steps/extract-values-search-step.test.ts index acb888a5d..0bf73808a 100644 --- a/packages/ai/src/steps/extract-values-search-step.test.ts +++ b/packages/ai/src/steps/extract-values-search-step.test.ts @@ -1,7 +1,7 @@ import { RuntimeContext } from '@mastra/core/runtime-context'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { extractValuesSearchStep } from './extract-values-search-step'; import type { AnalystRuntimeContext } from '../workflows/analyst-workflow'; +import { extractValuesSearchStep } from './extract-values-search-step'; // Mock the stored-values package vi.mock('@buster/stored-values/search', () => { diff --git a/packages/ai/src/steps/think-and-prep-todos.int.test.ts b/packages/ai/src/steps/think-and-prep-todos.int.test.ts index a09d8b571..b84b82fdf 100644 --- a/packages/ai/src/steps/think-and-prep-todos.int.test.ts +++ b/packages/ai/src/steps/think-and-prep-todos.int.test.ts @@ -1,8 +1,8 @@ import { RuntimeContext } from '@mastra/core/runtime-context'; import { initLogger } from 'braintrust'; import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest'; -import { thinkAndPrepStep } from './think-and-prep-step'; import type { AnalystRuntimeContext } from '../workflows/analyst-workflow'; +import { thinkAndPrepStep } from './think-and-prep-step'; describe('Think and Prep Step - Todos in Message History Integration', { timeout: 30000 }, () => { beforeAll(() => { diff --git a/packages/ai/src/tools/communication-tools/done-tool-streaming.test.ts b/packages/ai/src/tools/communication-tools/done-tool-streaming.test.ts index 51b6669ce..45124a5c6 100644 --- a/packages/ai/src/tools/communication-tools/done-tool-streaming.test.ts +++ b/packages/ai/src/tools/communication-tools/done-tool-streaming.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest'; -import { parseStreamingArgs } from './done-tool'; import { validateArrayAccess } from '../../utils/validation-helpers'; +import { parseStreamingArgs } from './done-tool'; describe('Done Tool Streaming Parser', () => { test('should return null for empty or invalid input', () => { diff --git a/packages/ai/src/tools/communication-tools/message-user-clarifying-question.test.ts b/packages/ai/src/tools/communication-tools/message-user-clarifying-question.test.ts index 826208e6b..8a6fe898f 100644 --- a/packages/ai/src/tools/communication-tools/message-user-clarifying-question.test.ts +++ b/packages/ai/src/tools/communication-tools/message-user-clarifying-question.test.ts @@ -49,7 +49,8 @@ describe('Message User Clarifying Question Tool Unit Tests', () => { test('should execute successfully with valid question', async () => { const result = await messageUserClarifyingQuestion.execute({ context: { - clarifying_question: '## Which metric would you like to focus on?\n\n- Revenue: Total sales revenue\n- Profit: Net profit after costs\n- Volume: Number of units sold', + clarifying_question: + '## Which metric would you like to focus on?\n\n- Revenue: Total sales revenue\n- Profit: Net profit after costs\n- Volume: Number of units sold', }, runtimeContext: {} as any, }); @@ -58,8 +59,6 @@ describe('Message User Clarifying Question Tool Unit Tests', () => { }); }); -describe.skip('Process Clarification Response Tool Tests (SKIPPED - Tool not implemented)', () => { -}); +describe.skip('Process Clarification Response Tool Tests (SKIPPED - Tool not implemented)', () => {}); -describe.skip('Should Ask Clarification Helper Tests (SKIPPED - Helper not implemented)', () => { -}); +describe.skip('Should Ask Clarification Helper Tests (SKIPPED - Helper not implemented)', () => {}); diff --git a/packages/ai/src/tools/communication-tools/message-user-clarifying-question.ts b/packages/ai/src/tools/communication-tools/message-user-clarifying-question.ts index ddd3dfd87..04b15590a 100644 --- a/packages/ai/src/tools/communication-tools/message-user-clarifying-question.ts +++ b/packages/ai/src/tools/communication-tools/message-user-clarifying-question.ts @@ -77,7 +77,9 @@ async function processMessageUserClarifyingQuestion(): Promise< // Main message user clarifying question function with tracing const executeMessageUserClarifyingQuestion = wrapTraced( - async (clarifyingQuestion: string): Promise> => { + async ( + _clarifyingQuestion: string + ): Promise> => { return await processMessageUserClarifyingQuestion(); }, { name: 'message-user-clarifying-question' } @@ -91,7 +93,9 @@ export const messageUserClarifyingQuestion = createTool({ inputSchema: messageUserClarifyingQuestionInputSchema, outputSchema: messageUserClarifyingQuestionOutputSchema, execute: async ({ context }) => { - return await executeMessageUserClarifyingQuestion((context as z.infer).clarifying_question); + return await executeMessageUserClarifyingQuestion( + (context as z.infer).clarifying_question + ); }, }); diff --git a/packages/ai/src/tools/communication-tools/respond-without-analysis-streaming.test.ts b/packages/ai/src/tools/communication-tools/respond-without-analysis-streaming.test.ts index d4c2096c1..c4af0ec7a 100644 --- a/packages/ai/src/tools/communication-tools/respond-without-analysis-streaming.test.ts +++ b/packages/ai/src/tools/communication-tools/respond-without-analysis-streaming.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest'; -import { parseStreamingArgs } from './respond-without-analysis'; import { validateArrayAccess } from '../../utils/validation-helpers'; +import { parseStreamingArgs } from './respond-without-analysis'; describe('Respond Without Analysis Tool Streaming Parser', () => { test('should return null for empty or invalid input', () => { diff --git a/packages/ai/src/tools/database-tools/execute-sql-streaming.test.ts b/packages/ai/src/tools/database-tools/execute-sql-streaming.test.ts index 470fd1fa3..10d48dc04 100644 --- a/packages/ai/src/tools/database-tools/execute-sql-streaming.test.ts +++ b/packages/ai/src/tools/database-tools/execute-sql-streaming.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest'; -import { parseStreamingArgs } from './execute-sql'; import { validateArrayAccess } from '../../utils/validation-helpers'; +import { parseStreamingArgs } from './execute-sql'; describe('Execute SQL Tool Streaming Parser', () => { test('should return null for empty or invalid input', () => { diff --git a/packages/ai/src/tools/database-tools/sql-limit-helper.test.ts b/packages/ai/src/tools/database-tools/sql-limit-helper.test.ts index 1328d2144..babe367a8 100644 --- a/packages/ai/src/tools/database-tools/sql-limit-helper.test.ts +++ b/packages/ai/src/tools/database-tools/sql-limit-helper.test.ts @@ -1,8 +1,5 @@ import { describe, expect, test } from 'vitest'; -import { - ensureSqlLimit, - ensureSqlLimitsForMultiple, -} from './sql-limit-helper'; +import { ensureSqlLimit, ensureSqlLimitsForMultiple } from './sql-limit-helper'; describe('SQL Limit Helper', () => { describe('ensureSqlLimit', () => { diff --git a/packages/ai/src/tools/planning-thinking-tools/sequential-thinking-tool-streaming.test.ts b/packages/ai/src/tools/planning-thinking-tools/sequential-thinking-tool-streaming.test.ts index 8d8e189e4..d5641d8db 100644 --- a/packages/ai/src/tools/planning-thinking-tools/sequential-thinking-tool-streaming.test.ts +++ b/packages/ai/src/tools/planning-thinking-tools/sequential-thinking-tool-streaming.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest'; -import { parseStreamingArgs } from './sequential-thinking-tool'; import { validateArrayAccess } from '../../utils/validation-helpers'; +import { parseStreamingArgs } from './sequential-thinking-tool'; describe('Sequential Thinking Tool Streaming Parser', () => { test('should return null for empty or invalid input', () => { diff --git a/packages/ai/src/tools/visualization-tools/create-dashboards-file-tool.int.test.ts b/packages/ai/src/tools/visualization-tools/create-dashboards-file-tool.int.test.ts index 516777dfa..abf22cfc1 100644 --- a/packages/ai/src/tools/visualization-tools/create-dashboards-file-tool.int.test.ts +++ b/packages/ai/src/tools/visualization-tools/create-dashboards-file-tool.int.test.ts @@ -9,8 +9,8 @@ import { } from '@buster/database'; import type { RuntimeContext } from '@mastra/core/runtime-context'; import { afterEach, beforeEach, describe, expect, test } from 'vitest'; -import { createDashboards } from './create-dashboards-file-tool'; import { validateArrayAccess } from '../../utils/validation-helpers'; +import { createDashboards } from './create-dashboards-file-tool'; // Type for runtime context type MockRuntimeContext = { diff --git a/packages/ai/src/tools/visualization-tools/create-metrics-file-tool-streaming.test.ts b/packages/ai/src/tools/visualization-tools/create-metrics-file-tool-streaming.test.ts index 9087f6d92..e4d792062 100644 --- a/packages/ai/src/tools/visualization-tools/create-metrics-file-tool-streaming.test.ts +++ b/packages/ai/src/tools/visualization-tools/create-metrics-file-tool-streaming.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest'; -import { parseStreamingArgs } from './create-metrics-file-tool'; import { validateArrayAccess } from '../../utils/validation-helpers'; +import { parseStreamingArgs } from './create-metrics-file-tool'; describe('Create Metrics File Tool Streaming Parser', () => { test('should return null for empty or invalid input', () => { diff --git a/packages/ai/src/tools/visualization-tools/create-metrics-file-tool.int.test.ts b/packages/ai/src/tools/visualization-tools/create-metrics-file-tool.int.test.ts index 15ec8a61a..8bcd0efb5 100644 --- a/packages/ai/src/tools/visualization-tools/create-metrics-file-tool.int.test.ts +++ b/packages/ai/src/tools/visualization-tools/create-metrics-file-tool.int.test.ts @@ -1,8 +1,8 @@ import { randomUUID } from 'node:crypto'; import type { RuntimeContext } from '@mastra/core/runtime-context'; import { afterEach, beforeEach, describe, expect, test } from 'vitest'; -import { createMetrics } from './create-metrics-file-tool'; import { validateArrayAccess } from '../../utils/validation-helpers'; +import { createMetrics } from './create-metrics-file-tool'; describe('Create Metrics File Tool Integration Tests', () => { let mockRuntimeContext: Record; diff --git a/packages/ai/src/tools/visualization-tools/version-history-helpers.test.ts b/packages/ai/src/tools/visualization-tools/version-history-helpers.test.ts index fc13ffd93..bfd67f2ac 100644 --- a/packages/ai/src/tools/visualization-tools/version-history-helpers.test.ts +++ b/packages/ai/src/tools/visualization-tools/version-history-helpers.test.ts @@ -5,11 +5,7 @@ import { createInitialDashboardVersionHistory, createInitialMetricVersionHistory, } from './version-history-helpers'; -import type { - DashboardYml, - MetricYml, - VersionHistory, -} from './version-history-types'; +import type { DashboardYml, MetricYml, VersionHistory } from './version-history-types'; describe('Version History Helper Functions', () => { describe('Metric Version History JSONB Format', () => { diff --git a/packages/ai/src/utils/database/chunk-processor-deferred-response.test.ts b/packages/ai/src/utils/database/chunk-processor-deferred-response.test.ts index 25737d1a8..aa2c4a3be 100644 --- a/packages/ai/src/utils/database/chunk-processor-deferred-response.test.ts +++ b/packages/ai/src/utils/database/chunk-processor-deferred-response.test.ts @@ -6,8 +6,20 @@ import type { GenericToolSet } from './types'; describe('ChunkProcessor - Deferred doneTool Response', () => { test('should defer doneTool response when completed files exist', async () => { // Use null messageId to avoid database saves in unit tests - const availableTools = new Set(['createMetrics', 'doneTool', 'sequentialThinking', 'submitThoughts']); - const processor = new ChunkProcessor(null, [], [], [], undefined, availableTools); + const availableTools = new Set([ + 'createMetrics', + 'doneTool', + 'sequentialThinking', + 'submitThoughts', + ]); + const processor = new ChunkProcessor( + null, + [], + [], + [], + undefined, + availableTools + ); // First, start streaming a file creation const fileToolStart: TextStreamPart = { @@ -114,8 +126,20 @@ describe('ChunkProcessor - Deferred doneTool Response', () => { test('should not defer doneTool response when no completed files exist', async () => { // Use null messageId to avoid database saves in unit tests - const availableTools = new Set(['createMetrics', 'doneTool', 'sequentialThinking', 'submitThoughts']); - const processor = new ChunkProcessor(null, [], [], [], undefined, availableTools); + const availableTools = new Set([ + 'createMetrics', + 'doneTool', + 'sequentialThinking', + 'submitThoughts', + ]); + const processor = new ChunkProcessor( + null, + [], + [], + [], + undefined, + availableTools + ); // Start streaming doneTool without any files const doneToolStart: TextStreamPart = { @@ -153,8 +177,20 @@ describe('ChunkProcessor - Deferred doneTool Response', () => { test('should not defer doneTool response when files exist but are not completed', async () => { // Use null messageId to avoid database saves in unit tests - const availableTools = new Set(['createMetrics', 'doneTool', 'sequentialThinking', 'submitThoughts']); - const processor = new ChunkProcessor(null, [], [], [], undefined, availableTools); + const availableTools = new Set([ + 'createMetrics', + 'doneTool', + 'sequentialThinking', + 'submitThoughts', + ]); + const processor = new ChunkProcessor( + null, + [], + [], + [], + undefined, + availableTools + ); // Add a file that's still loading const fileToolCall: TextStreamPart = { diff --git a/packages/ai/src/utils/database/chunk-processor-escape-normalization.test.ts b/packages/ai/src/utils/database/chunk-processor-escape-normalization.test.ts index fde059816..3be456d07 100644 --- a/packages/ai/src/utils/database/chunk-processor-escape-normalization.test.ts +++ b/packages/ai/src/utils/database/chunk-processor-escape-normalization.test.ts @@ -12,7 +12,14 @@ describe('ChunkProcessor - Escape Normalization', () => { beforeEach(() => { const availableTools = new Set(['sequential-thinking', 'submitThoughts']); - processor = new ChunkProcessor('test-message-id', [], [], [], undefined, availableTools); + processor = new ChunkProcessor( + 'test-message-id', + [], + [], + [], + undefined, + availableTools + ); }); it('should normalize double-escaped newlines in sequential thinking tool', async () => { diff --git a/packages/ai/src/utils/database/chunk-processor-failure-handling.test.ts b/packages/ai/src/utils/database/chunk-processor-failure-handling.test.ts index 4d75f23b8..d8368016b 100644 --- a/packages/ai/src/utils/database/chunk-processor-failure-handling.test.ts +++ b/packages/ai/src/utils/database/chunk-processor-failure-handling.test.ts @@ -1,8 +1,8 @@ -import { beforeEach, describe, expect, test } from 'vitest'; import type { ChatMessageReasoningMessage, ChatMessageResponseMessage, } from '@buster/server-shared/chats'; +import { beforeEach, describe, expect, test } from 'vitest'; import { ChunkProcessor } from './chunk-processor'; import { determineToolStatus, diff --git a/packages/ai/src/utils/database/chunk-processor-sql.test.ts b/packages/ai/src/utils/database/chunk-processor-sql.test.ts index 48f59cef2..7a6a11cbc 100644 --- a/packages/ai/src/utils/database/chunk-processor-sql.test.ts +++ b/packages/ai/src/utils/database/chunk-processor-sql.test.ts @@ -1,7 +1,7 @@ -import { describe, expect, it } from 'vitest'; import type { ChatMessageReasoningMessage } from '@buster/server-shared/chats'; -import { ChunkProcessor } from './chunk-processor'; +import { describe, expect, it } from 'vitest'; import { validateArrayAccess } from '../validation-helpers'; +import { ChunkProcessor } from './chunk-processor'; describe('ChunkProcessor SQL Reasoning Entry Creation', () => { it('should create SQL reasoning entry with statements array', () => { diff --git a/packages/ai/src/utils/database/chunk-processor.test.ts b/packages/ai/src/utils/database/chunk-processor.test.ts index 38e55c97f..13942a4c9 100644 --- a/packages/ai/src/utils/database/chunk-processor.test.ts +++ b/packages/ai/src/utils/database/chunk-processor.test.ts @@ -113,7 +113,14 @@ describe('ChunkProcessor', () => { ]; const availableTools = new Set(['sequentialThinking']); - const processor = new ChunkProcessor(mockMessageId, initialMessages, [], [], undefined, availableTools); + const processor = new ChunkProcessor( + mockMessageId, + initialMessages, + [], + [], + undefined, + availableTools + ); // Process a new tool call await processor.processChunk({ @@ -244,7 +251,14 @@ describe('ChunkProcessor - Cross-Step Message Accumulation', () => { it('should properly accumulate messages across workflow steps without duplicates', async () => { // Step 1: think-and-prep processes initial messages const availableTools = new Set(['sequentialThinking']); - const thinkAndPrepProcessor = new ChunkProcessor(mockMessageId, [], [], [], undefined, availableTools); + const thinkAndPrepProcessor = new ChunkProcessor( + mockMessageId, + [], + [], + [], + undefined, + availableTools + ); const initialMessages: CoreMessage[] = [ { role: 'user', content: 'What are the top products?' }, @@ -361,7 +375,14 @@ describe('ChunkProcessor - Cross-Step Message Accumulation', () => { // Simulate analyst-step receiving these messages const availableTools = new Set(['executeSql']); - const analystProcessor = new ChunkProcessor(mockMessageId, [], [], [], undefined, availableTools); + const analystProcessor = new ChunkProcessor( + mockMessageId, + [], + [], + [], + undefined, + availableTools + ); analystProcessor.setInitialMessages(messagesFromThinkAndPrep); expect(analystProcessor.getAccumulatedMessages()).toHaveLength(4); diff --git a/packages/ai/src/utils/database/chunk-processor.ts b/packages/ai/src/utils/database/chunk-processor.ts index c1c9c099e..7f89b23b5 100644 --- a/packages/ai/src/utils/database/chunk-processor.ts +++ b/packages/ai/src/utils/database/chunk-processor.ts @@ -13,7 +13,6 @@ import { } from '../file-selection'; import { normalizeEscapedText } from '../streaming/escape-normalizer'; import { OptimisticJsonParser, getOptimisticValue } from '../streaming/optimistic-json-parser'; -import { extractResponseMessages } from './format-llm-messages-as-reasoning'; import type { AssistantMessageContent, GenericToolSet, @@ -2018,18 +2017,18 @@ export class ChunkProcessor { // Update the existing file with results appended const fileObj = file as { file?: { text?: string } }; const currentContent = fileObj.file?.text || ''; - + // Append results to the existing content if (fileObj.file) { - fileObj.file.text = currentContent + '\n\n' + resultsYaml; + fileObj.file.text = `${currentContent}\n\n${resultsYaml}`; } - + // Update the entry title and secondary title if ('title' in entry) { - (entry as any).title = title; + (entry as ReasoningEntry & { title: string }).title = title; } if ('secondary_title' in entry && secondaryTitle) { - (entry as any).secondary_title = secondaryTitle; + (entry as ReasoningEntry & { secondary_title: string }).secondary_title = secondaryTitle; } } catch (error) { console.error('Error updating SQL file with results:', { diff --git a/packages/ai/src/utils/database/format-llm-messages-as-reasoning.ts b/packages/ai/src/utils/database/format-llm-messages-as-reasoning.ts index a9016b092..1f416cfed 100644 --- a/packages/ai/src/utils/database/format-llm-messages-as-reasoning.ts +++ b/packages/ai/src/utils/database/format-llm-messages-as-reasoning.ts @@ -90,10 +90,11 @@ function formatMessageAsReasoningEntry( if (args.thought) { const thoughtNumber = args.thoughtNumber as number; const totalThoughts = args.totalThoughts as number; - const title = thoughtNumber && totalThoughts - ? `Thought ${thoughtNumber} of ${totalThoughts}` - : 'Thinking...'; - + const title = + thoughtNumber && totalThoughts + ? `Thought ${thoughtNumber} of ${totalThoughts}` + : 'Thinking...'; + const textEntry: ReasoningTextEntry = { id: toolCall.toolCallId, type: 'text', diff --git a/packages/ai/src/utils/database/types.ts b/packages/ai/src/utils/database/types.ts index 831b99699..624141566 100644 --- a/packages/ai/src/utils/database/types.ts +++ b/packages/ai/src/utils/database/types.ts @@ -262,9 +262,12 @@ export function extractFileResultsFromToolResult(toolResult: unknown): Array<{ if (file && typeof file === 'object' && 'id' in file) { const fileObj = file as Record; const id = typeof fileObj.id === 'string' ? fileObj.id : String(fileObj.id); - + // Check if this individual file has an error property or success: false - if (('error' in fileObj && fileObj.error) || ('success' in fileObj && fileObj.success === false)) { + if ( + ('error' in fileObj && fileObj.error) || + ('success' in fileObj && fileObj.success === false) + ) { fileResults.push({ id, status: 'failed' as const, diff --git a/packages/ai/src/utils/file-selection.test.ts b/packages/ai/src/utils/file-selection.test.ts index 1796399f6..bcd4251d5 100644 --- a/packages/ai/src/utils/file-selection.test.ts +++ b/packages/ai/src/utils/file-selection.test.ts @@ -309,13 +309,13 @@ describe('file-selection', () => { const selected = selectFilesForResponse(files); expect(selected).toHaveLength(2); - - const dashboard = selected.find(f => f.fileType === 'dashboard'); - const metric = selected.find(f => f.fileType === 'metric'); - + + const dashboard = selected.find((f) => f.fileType === 'dashboard'); + const metric = selected.find((f) => f.fileType === 'metric'); + expect(dashboard?.versionNumber).toBe(2); expect(dashboard?.operation).toBe('modified'); - + expect(metric?.versionNumber).toBe(3); expect(metric?.operation).toBe('created'); }); diff --git a/packages/ai/src/utils/file-selection.ts b/packages/ai/src/utils/file-selection.ts index 524622691..3b0052f85 100644 --- a/packages/ai/src/utils/file-selection.ts +++ b/packages/ai/src/utils/file-selection.ts @@ -411,8 +411,8 @@ export function selectFilesForResponse( // Check if any standalone metrics are the result of deduplication const originalMetrics = files.filter((f) => f.fileType === 'metric'); - const hasDeduplicatedMetrics = standaloneMetrics.some(metric => { - const duplicates = originalMetrics.filter(m => m.id === metric.id); + const hasDeduplicatedMetrics = standaloneMetrics.some((metric) => { + const duplicates = originalMetrics.filter((m) => m.id === metric.id); return duplicates.length > 1; }); @@ -420,7 +420,9 @@ export function selectFilesForResponse( // Include all standalone metrics when deduplication occurred selectedFiles.push(...standaloneMetrics); } else { - const standaloneModifiedMetrics = standaloneMetrics.filter(m => m.operation === 'modified'); + const standaloneModifiedMetrics = standaloneMetrics.filter( + (m) => m.operation === 'modified' + ); selectedFiles.push(...standaloneModifiedMetrics); } } else { diff --git a/packages/ai/src/utils/memory/ai-sdk-bundling.test.ts b/packages/ai/src/utils/memory/ai-sdk-bundling.test.ts index 7e25eea23..7a23254c2 100644 --- a/packages/ai/src/utils/memory/ai-sdk-bundling.test.ts +++ b/packages/ai/src/utils/memory/ai-sdk-bundling.test.ts @@ -1,7 +1,7 @@ import type { CoreMessage } from 'ai'; import { describe, expect, test } from 'vitest'; -import { extractMessageHistory } from './message-history'; import { validateArrayAccess } from '../validation-helpers'; +import { extractMessageHistory } from './message-history'; describe('AI SDK Message Bundling Issues', () => { test('identify when AI SDK returns bundled messages', () => { diff --git a/packages/ai/src/utils/memory/message-converters-error-handling.test.ts b/packages/ai/src/utils/memory/message-converters-error-handling.test.ts index c5747006d..def398b17 100644 --- a/packages/ai/src/utils/memory/message-converters-error-handling.test.ts +++ b/packages/ai/src/utils/memory/message-converters-error-handling.test.ts @@ -1,8 +1,5 @@ import { afterAll, afterEach, describe, expect, test, vi } from 'vitest'; -import { - convertToolCallToMessage, - extractMessagesFromToolCalls, -} from './message-converters'; +import { convertToolCallToMessage, extractMessagesFromToolCalls } from './message-converters'; describe('message-converters error handling', () => { // Mock console.error to verify error logging diff --git a/packages/ai/src/utils/memory/message-converters.test.ts b/packages/ai/src/utils/memory/message-converters.test.ts index fcce89a43..217a21701 100644 --- a/packages/ai/src/utils/memory/message-converters.test.ts +++ b/packages/ai/src/utils/memory/message-converters.test.ts @@ -1,13 +1,10 @@ -import type { AssistantContent } from 'ai'; -import { describe, expect, it } from 'vitest'; import type { ChatMessageReasoningMessage, ChatMessageResponseMessage, } from '@buster/server-shared/chats'; -import { - convertToolCallToMessage, - extractMessagesFromToolCalls, -} from './message-converters'; +import type { AssistantContent } from 'ai'; +import { describe, expect, it } from 'vitest'; +import { convertToolCallToMessage, extractMessagesFromToolCalls } from './message-converters'; // Extract ToolCall type from AssistantContent type ToolCall = Extract; @@ -156,7 +153,10 @@ describe('message-converters', () => { expect(result).not.toBeNull(); expect(result?.type).toBe('reasoning'); - const reasoning = result?.message as Extract; + const reasoning = result?.message as Extract< + ChatMessageReasoningMessage, + { type: 'files' } + >; expect(reasoning).toMatchObject({ id: 'test-id-6', type: 'files', @@ -190,7 +190,10 @@ describe('message-converters', () => { const result = convertToolCallToMessage(toolCall, toolResult, 'completed'); - const reasoning = result?.message as Extract; + const reasoning = result?.message as Extract< + ChatMessageReasoningMessage, + { type: 'files' } + >; expect(reasoning.title).toBe('Created 1 metric'); expect(reasoning.secondary_title).toBeUndefined(); }); @@ -215,7 +218,10 @@ describe('message-converters', () => { expect(result).not.toBeNull(); expect(result?.type).toBe('reasoning'); - const reasoning = result?.message as Extract; + const reasoning = result?.message as Extract< + ChatMessageReasoningMessage, + { type: 'files' } + >; expect(reasoning.files!['dashboard-1']!.file_type).toBe('dashboard'); }); }); @@ -237,7 +243,10 @@ describe('message-converters', () => { const result = convertToolCallToMessage(toolCall, toolResult, 'completed'); - const reasoning = result?.message as Extract; + const reasoning = result?.message as Extract< + ChatMessageReasoningMessage, + { type: 'files' } + >; expect(reasoning.title).toBe('Modified 1 metric'); expect(reasoning.files!['metric-1']!.version_number).toBe(2); }); @@ -256,7 +265,10 @@ describe('message-converters', () => { const result = convertToolCallToMessage(toolCall, toolResult, 'completed'); - const reasoning = result?.message as Extract; + const reasoning = result?.message as Extract< + ChatMessageReasoningMessage, + { type: 'files' } + >; expect(reasoning.title).toBe('Modified 0 dashboards'); expect(reasoning.secondary_title).toBe('1 failed'); expect(reasoning.status).toBe('completed'); diff --git a/packages/ai/src/utils/memory/message-converters.ts b/packages/ai/src/utils/memory/message-converters.ts index 4cb9cc3f5..57385a1e8 100644 --- a/packages/ai/src/utils/memory/message-converters.ts +++ b/packages/ai/src/utils/memory/message-converters.ts @@ -128,7 +128,7 @@ export function convertToolCallToMessage( message: parsed.message, }; return { type: 'response', message: responseMessage }; - } catch (error) { + } catch (_) { return null; } } @@ -144,7 +144,7 @@ export function convertToolCallToMessage( message: parsed.message, }; return { type: 'response', message: responseMessage }; - } catch (error) { + } catch (_error) { return null; } } @@ -164,7 +164,7 @@ export function convertToolCallToMessage( finished_reasoning: !parsed.nextThoughtNeeded, }; return { type: 'reasoning', message: reasoningMessage }; - } catch (error) { + } catch (_error) { return null; } } @@ -223,7 +223,7 @@ export function convertToolCallToMessage( files, }; return { type: 'reasoning', message: reasoningMessage }; - } catch (error) { + } catch (_error) { return null; } } @@ -241,7 +241,7 @@ export function convertToolCallToMessage( status, }; return { type: 'reasoning', message: reasoningMessage }; - } catch (error) { + } catch (_error) { return null; } } @@ -300,7 +300,7 @@ export function convertToolCallToMessage( files, }; return { type: 'reasoning', message: reasoningMessage }; - } catch (error) { + } catch (_error) { return null; } } @@ -359,7 +359,7 @@ export function convertToolCallToMessage( files, }; return { type: 'reasoning', message: reasoningMessage }; - } catch (error) { + } catch (_error) { return null; } } @@ -418,7 +418,7 @@ export function convertToolCallToMessage( files, }; return { type: 'reasoning', message: reasoningMessage }; - } catch (error) { + } catch (_error) { return null; } } diff --git a/packages/ai/src/utils/memory/message-history.test.ts b/packages/ai/src/utils/memory/message-history.test.ts index 585ed5ab3..6d2fb616f 100644 --- a/packages/ai/src/utils/memory/message-history.test.ts +++ b/packages/ai/src/utils/memory/message-history.test.ts @@ -1,5 +1,6 @@ import type { CoreMessage } from 'ai'; import { describe, expect, test } from 'vitest'; +import { hasToolCallId, validateArrayAccess } from '../validation-helpers'; import { extractMessageHistory, getAllToolsUsed, @@ -9,7 +10,6 @@ import { properlyInterleaveMessages, unbundleMessages, } from './message-history'; -import { hasToolCallId, validateArrayAccess } from '../validation-helpers'; describe('Message History Utilities', () => { describe('Message Format Validation', () => { diff --git a/packages/ai/src/utils/memory/stored-values-to-messages.test.ts b/packages/ai/src/utils/memory/stored-values-to-messages.test.ts index 7d090cf96..3e8831064 100644 --- a/packages/ai/src/utils/memory/stored-values-to-messages.test.ts +++ b/packages/ai/src/utils/memory/stored-values-to-messages.test.ts @@ -78,7 +78,7 @@ name [Red Bull, Monster Energy]`; const fileId = reasoningMessage.file_ids[0]!; expect(reasoningMessage.files[fileId]).toBeDefined(); - const file = reasoningMessage.files[fileId]! + const file = reasoningMessage.files[fileId]!; expect(file.file_type).toBe('agent-action'); expect(file.file_name).toBe('stored-values-search'); expect(file.version_number).toBe(1); @@ -112,7 +112,7 @@ name [Red Bull, Monster Energy]`; const reasoningMessage = createStoredValuesReasoningMessage(searchResults); const fileId = reasoningMessage.file_ids[0]!; - const file = reasoningMessage.files[fileId]! + const file = reasoningMessage.files[fileId]!; expect(file.id).toBe(fileId); expect(file.file_type).toBe('agent-action'); @@ -136,7 +136,7 @@ name [Red Bull, Monster Energy]`; // Verify file structure const fileId = reasoningMessage.file_ids[0]!; - const file = reasoningMessage.files[fileId]! + const file = reasoningMessage.files[fileId]!; expect(file).toHaveProperty('id'); expect(file).toHaveProperty('file_type'); expect(file).toHaveProperty('file_name'); diff --git a/packages/ai/src/utils/memory/todos-to-messages.test.ts b/packages/ai/src/utils/memory/todos-to-messages.test.ts index 1934a3d6d..93d9b71ba 100644 --- a/packages/ai/src/utils/memory/todos-to-messages.test.ts +++ b/packages/ai/src/utils/memory/todos-to-messages.test.ts @@ -1,9 +1,6 @@ import { describe, expect, test } from 'vitest'; -import { - createTodoReasoningMessage, - createTodoToolCallMessage, -} from './todos-to-messages'; import { validateArrayAccess } from '../validation-helpers'; +import { createTodoReasoningMessage, createTodoToolCallMessage } from './todos-to-messages'; describe('Todos to Message Conversion', () => { const sampleTodos = `[ ] Determine how "sales" is identified diff --git a/packages/ai/src/utils/memory/workflow-message-flow.test.ts b/packages/ai/src/utils/memory/workflow-message-flow.test.ts index 40b5228b0..8081de214 100644 --- a/packages/ai/src/utils/memory/workflow-message-flow.test.ts +++ b/packages/ai/src/utils/memory/workflow-message-flow.test.ts @@ -6,8 +6,8 @@ import type { ToolResultPart, } from 'ai'; import { describe, expect, test } from 'vitest'; -import { extractMessageHistory } from './message-history'; import { validateArrayAccess } from '../validation-helpers'; +import { extractMessageHistory } from './message-history'; describe('Workflow Message Flow', () => { test('should maintain sequential order when passing messages between steps', () => { diff --git a/packages/ai/src/utils/retry/retry-helpers.test.ts b/packages/ai/src/utils/retry/retry-helpers.test.ts index 54adb5e4e..3d6433f06 100644 --- a/packages/ai/src/utils/retry/retry-helpers.test.ts +++ b/packages/ai/src/utils/retry/retry-helpers.test.ts @@ -432,7 +432,9 @@ describe('retry-helpers', () => { const healingMessage: CoreMessage = { role: 'tool', - content: [{ type: 'tool-result', toolCallId: '123', toolName: 'testTool', result: 'Result' }], + content: [ + { type: 'tool-result', toolCallId: '123', toolName: 'testTool', result: 'Result' }, + ], }; const messages: CoreMessage[] = [ diff --git a/packages/ai/src/utils/streaming/optimistic-json-parser-edge-cases.test.ts b/packages/ai/src/utils/streaming/optimistic-json-parser-edge-cases.test.ts index 1887d04a3..f36799e1c 100644 --- a/packages/ai/src/utils/streaming/optimistic-json-parser-edge-cases.test.ts +++ b/packages/ai/src/utils/streaming/optimistic-json-parser-edge-cases.test.ts @@ -1,8 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { - OptimisticJsonParser, - getOptimisticValue, -} from './optimistic-json-parser'; +import { OptimisticJsonParser, getOptimisticValue } from './optimistic-json-parser'; describe('OptimisticJsonParser - Edge Cases and Special Characters', () => { describe('Special Characters and Escape Sequences', () => { diff --git a/packages/ai/src/utils/streaming/optimistic-json-parser-stress.test.ts b/packages/ai/src/utils/streaming/optimistic-json-parser-stress.test.ts index 1857767dd..a3bfa6046 100644 --- a/packages/ai/src/utils/streaming/optimistic-json-parser-stress.test.ts +++ b/packages/ai/src/utils/streaming/optimistic-json-parser-stress.test.ts @@ -1,8 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { - OptimisticJsonParser, - getOptimisticValue, -} from './optimistic-json-parser'; +import { OptimisticJsonParser, getOptimisticValue } from './optimistic-json-parser'; describe('OptimisticJsonParser - Stress Tests and Complex Scenarios', () => { describe('Many Keys Streaming', () => { diff --git a/packages/ai/src/utils/streaming/optimistic-json-parser.test.ts b/packages/ai/src/utils/streaming/optimistic-json-parser.test.ts index 1f07dcc13..a7f60b317 100644 --- a/packages/ai/src/utils/streaming/optimistic-json-parser.test.ts +++ b/packages/ai/src/utils/streaming/optimistic-json-parser.test.ts @@ -1,8 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { - OptimisticJsonParser, - getOptimisticValue, -} from './optimistic-json-parser'; +import { OptimisticJsonParser, getOptimisticValue } from './optimistic-json-parser'; describe('OptimisticJsonParser', () => { describe('parse', () => { diff --git a/packages/ai/src/workflows/analyst-workflow.int.test.ts b/packages/ai/src/workflows/analyst-workflow.int.test.ts index 030f59980..95af2b528 100644 --- a/packages/ai/src/workflows/analyst-workflow.int.test.ts +++ b/packages/ai/src/workflows/analyst-workflow.int.test.ts @@ -5,9 +5,7 @@ import type { CoreMessage } from 'ai'; import { initLogger, wrapTraced } from 'braintrust'; import { afterAll, beforeAll, describe, expect, test } from 'vitest'; import { getRawLlmMessagesByMessageId } from '../'; -import analystWorkflow, { - type AnalystRuntimeContext, -} from './analyst-workflow'; +import analystWorkflow, { type AnalystRuntimeContext } from './analyst-workflow'; describe('Analyst Workflow Integration Tests', () => { beforeAll(() => { @@ -140,9 +138,22 @@ describe('Analyst Workflow Integration Tests', () => { console.log('\n=== DATABASE SAVE VERIFICATION ==='); console.log('Message ID:', messageId); - console.log('Raw LLM Messages count:', Array.isArray(updatedMessage[0]!.rawLlmMessages) ? updatedMessage[0]!.rawLlmMessages.length : 0); - console.log('Reasoning entries count:', Array.isArray(updatedMessage[0]!.reasoning) ? updatedMessage[0]!.reasoning.length : 0); - console.log('Response messages count:', Array.isArray(updatedMessage[0]!.responseMessages) ? updatedMessage[0]!.responseMessages.length : 0); + console.log( + 'Raw LLM Messages count:', + Array.isArray(updatedMessage[0]!.rawLlmMessages) + ? updatedMessage[0]!.rawLlmMessages.length + : 0 + ); + console.log( + 'Reasoning entries count:', + Array.isArray(updatedMessage[0]!.reasoning) ? updatedMessage[0]!.reasoning.length : 0 + ); + console.log( + 'Response messages count:', + Array.isArray(updatedMessage[0]!.responseMessages) + ? updatedMessage[0]!.responseMessages.length + : 0 + ); // Check reasoning entries for partial content if (updatedMessage[0]!.reasoning && Array.isArray(updatedMessage[0]!.reasoning)) { diff --git a/packages/ai/src/workflows/message-bundling-debug.test.ts b/packages/ai/src/workflows/message-bundling-debug.test.ts index e562d3627..e5c5fd035 100644 --- a/packages/ai/src/workflows/message-bundling-debug.test.ts +++ b/packages/ai/src/workflows/message-bundling-debug.test.ts @@ -118,14 +118,12 @@ describe('Message Bundling Debug', () => { : 'text' ); if (msg.role === 'assistant' && Array.isArray(msg.content)) { - (msg.content as any[]).forEach( - (item: any, j) => { - if (item.type === 'tool-call') { - const toolCall = item as ToolCallPart; - console.log(` [${j}] tool-call: ${toolCall.toolName} (${toolCall.toolCallId})`); - } + (msg.content as any[]).forEach((item: any, j) => { + if (item.type === 'tool-call') { + const toolCall = item as ToolCallPart; + console.log(` [${j}] tool-call: ${toolCall.toolName} (${toolCall.toolCallId})`); } - ); + }); } }); diff --git a/packages/ai/src/workflows/workflow-message-accumulation.test.ts b/packages/ai/src/workflows/workflow-message-accumulation.test.ts index e495265d0..1e1c0bcb7 100644 --- a/packages/ai/src/workflows/workflow-message-accumulation.test.ts +++ b/packages/ai/src/workflows/workflow-message-accumulation.test.ts @@ -20,7 +20,14 @@ describe('Workflow Message Accumulation Integration', () => { it('should not create duplicate messages when passing from think-and-prep to analyst step', async () => { // Step 1: Simulate think-and-prep step processing const availableTools = new Set(['sequentialThinking', 'executeSql']); - const thinkAndPrepProcessor = new ChunkProcessor(mockMessageId, [], [], [], undefined, availableTools); + const thinkAndPrepProcessor = new ChunkProcessor( + mockMessageId, + [], + [], + [], + undefined, + availableTools + ); // Initial user message const userMessage: CoreMessage = { diff --git a/packages/data-source/src/adapters/base.test.ts b/packages/data-source/src/adapters/base.test.ts index 58ee42e85..8f67f2fde 100644 --- a/packages/data-source/src/adapters/base.test.ts +++ b/packages/data-source/src/adapters/base.test.ts @@ -1,12 +1,8 @@ import { beforeEach, describe, expect, it } from 'vitest'; +import { DataSourceType } from '../types/credentials'; +import type { Credentials, MySQLCredentials, PostgreSQLCredentials } from '../types/credentials'; import { BaseAdapter } from './base'; import type { AdapterQueryResult } from './base'; -import { DataSourceType } from '../types/credentials'; -import type { - Credentials, - MySQLCredentials, - PostgreSQLCredentials, -} from '../types/credentials'; // Mock implementation of BaseAdapter for testing class MockAdapter extends BaseAdapter { diff --git a/packages/data-source/src/adapters/bigquery.int.test.ts b/packages/data-source/src/adapters/bigquery.int.test.ts index 2e56fb1ab..dd1bc0603 100644 --- a/packages/data-source/src/adapters/bigquery.int.test.ts +++ b/packages/data-source/src/adapters/bigquery.int.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { BigQueryAdapter } from './bigquery'; import { DataSourceType } from '../types/credentials'; import type { BigQueryCredentials } from '../types/credentials'; +import { BigQueryAdapter } from './bigquery'; // Check if BigQuery test credentials are available const hasBigQueryCredentials = !!( @@ -132,4 +132,4 @@ describe('BigQueryAdapter Integration', () => { }, TEST_TIMEOUT ); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/bigquery.test.ts b/packages/data-source/src/adapters/bigquery.test.ts index ae0c0c758..85221c6d5 100644 --- a/packages/data-source/src/adapters/bigquery.test.ts +++ b/packages/data-source/src/adapters/bigquery.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { BigQueryAdapter } from './bigquery'; import { DataSourceType } from '../types/credentials'; import type { BigQueryCredentials } from '../types/credentials'; +import { BigQueryAdapter } from './bigquery'; // Create mock BigQuery instance const mockBigQuery = { @@ -169,7 +169,7 @@ describe('BigQueryAdapter', () => { jobTimeoutMs: 60000, useLegacySql: false, }); - + expect(result).toEqual({ rows: mockRows, rowCount: 1, @@ -330,7 +330,7 @@ describe('BigQueryAdapter', () => { }; await adapter.initialize(credentials); - + const mockJob = { getQueryResults: vi.fn().mockResolvedValueOnce([[]]), }; @@ -354,7 +354,7 @@ describe('BigQueryAdapter', () => { }; await adapter.initialize(credentials); - + mockBigQuery.createQueryJob.mockRejectedValueOnce(new Error('Connection test failed')); const result = await adapter.testConnection(); @@ -386,9 +386,9 @@ describe('BigQueryAdapter', () => { }; await adapter.initialize(credentials); - + const introspector = adapter.introspect(); - + // Just verify it returns an introspector with the correct interface expect(introspector).toBeDefined(); expect(introspector.getDatabases).toBeDefined(); @@ -409,4 +409,4 @@ describe('BigQueryAdapter', () => { expect(adapter.getDataSourceType()).toBe(DataSourceType.BigQuery); }); }); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/factory.test.ts b/packages/data-source/src/adapters/factory.test.ts index 4a12c9c70..f0e7f2cf5 100644 --- a/packages/data-source/src/adapters/factory.test.ts +++ b/packages/data-source/src/adapters/factory.test.ts @@ -1,9 +1,4 @@ import { describe, expect, it } from 'vitest'; -import { - createAdapterInstance, - getSupportedTypes, - isSupported, -} from './factory'; import { DataSourceType } from '../types/credentials'; import type { BigQueryCredentials, @@ -14,6 +9,7 @@ import type { SQLServerCredentials, SnowflakeCredentials, } from '../types/credentials'; +import { createAdapterInstance, getSupportedTypes, isSupported } from './factory'; // Type for testing unsupported data source types type UnsupportedCredentials = { diff --git a/packages/data-source/src/adapters/max-rows-limiting.test.ts b/packages/data-source/src/adapters/max-rows-limiting.test.ts index 397433d96..e44a360d3 100644 --- a/packages/data-source/src/adapters/max-rows-limiting.test.ts +++ b/packages/data-source/src/adapters/max-rows-limiting.test.ts @@ -244,12 +244,16 @@ describe('MaxRows Limiting Tests', () => { }); mockConnection.execute.mockImplementation( - (options: { sqlText: string; binds?: unknown; complete: (err?: unknown, stmt?: unknown, rows?: unknown[]) => void }) => { + (options: { + sqlText: string; + binds?: unknown; + complete: (err?: unknown, stmt?: unknown, rows?: unknown[]) => void; + }) => { // The new Snowflake adapter doesn't use streaming for maxRows // It returns all rows and limits in memory options.complete(undefined, mockStatement, [ { id: 1, name: 'User 1' }, - { id: 2, name: 'User 2' } + { id: 2, name: 'User 2' }, ]); } ); diff --git a/packages/data-source/src/adapters/mysql.int.test.ts b/packages/data-source/src/adapters/mysql.int.test.ts index 080dc99c8..d266a9288 100644 --- a/packages/data-source/src/adapters/mysql.int.test.ts +++ b/packages/data-source/src/adapters/mysql.int.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { MySQLAdapter } from './mysql'; import { DataSourceType } from '../types/credentials'; import type { MySQLCredentials } from '../types/credentials'; +import { MySQLAdapter } from './mysql'; // Check if MySQL test credentials are available const hasMySQLCredentials = !!( @@ -139,4 +139,4 @@ describe('MySQLAdapter Integration', () => { }, TEST_TIMEOUT ); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/mysql.test.ts b/packages/data-source/src/adapters/mysql.test.ts index 93a3f0ffc..3419957bb 100644 --- a/packages/data-source/src/adapters/mysql.test.ts +++ b/packages/data-source/src/adapters/mysql.test.ts @@ -1,8 +1,8 @@ +import mysql from 'mysql2/promise'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { MySQLAdapter } from './mysql'; import { DataSourceType } from '../types/credentials'; import type { MySQLCredentials } from '../types/credentials'; -import mysql from 'mysql2/promise'; +import { MySQLAdapter } from './mysql'; // Mock mysql2/promise module vi.mock('mysql2/promise'); @@ -15,7 +15,7 @@ describe('MySQLAdapter', () => { beforeEach(() => { vi.clearAllMocks(); adapter = new MySQLAdapter(); - + // Create mock connection for each test mockConnection = { connect: vi.fn().mockResolvedValue(undefined), @@ -24,7 +24,7 @@ describe('MySQLAdapter', () => { end: vi.fn().mockResolvedValue(undefined), ping: vi.fn().mockResolvedValue(undefined), }; - + mockedMysql.createConnection = vi.fn().mockResolvedValue(mockConnection); }); @@ -164,7 +164,7 @@ describe('MySQLAdapter', () => { const result = await adapter.query('SELECT * FROM users'); expect(mockConnection.execute).toHaveBeenCalledWith('SELECT * FROM users', undefined); - + expect(result).toEqual({ rows: [{ id: 1, name: 'Test' }], rowCount: 1, @@ -177,10 +177,7 @@ describe('MySQLAdapter', () => { }); it('should execute parameterized query', async () => { - const mockResult = [ - [{ id: 1 }], - [{ name: 'id', type: 'LONG' }], - ]; + const mockResult = [[{ id: 1 }], [{ name: 'id', type: 'LONG' }]]; mockConnection.execute.mockResolvedValueOnce(mockResult); @@ -246,10 +243,7 @@ describe('MySQLAdapter', () => { }); it('should handle empty result sets', async () => { - const mockResult = [ - [], - [{ name: 'id', type: 'LONG' }], - ]; + const mockResult = [[], [{ name: 'id', type: 'LONG' }]]; mockConnection.execute.mockResolvedValueOnce(mockResult); @@ -282,7 +276,7 @@ describe('MySQLAdapter', () => { }; await adapter.initialize(credentials); - + mockConnection.execute.mockResolvedValueOnce([[], []]); const result = await adapter.testConnection(); @@ -301,7 +295,7 @@ describe('MySQLAdapter', () => { }; await adapter.initialize(credentials); - + mockConnection.execute.mockRejectedValueOnce(new Error('Connection test failed')); const result = await adapter.testConnection(); @@ -334,7 +328,7 @@ describe('MySQLAdapter', () => { }; await adapter.initialize(credentials); - + mockConnection.end.mockRejectedValueOnce(new Error('Close failed')); // Should not throw @@ -353,9 +347,9 @@ describe('MySQLAdapter', () => { }; await adapter.initialize(credentials); - + const introspector = adapter.introspect(); - + // Just verify it returns an introspector with the correct interface expect(introspector).toBeDefined(); expect(introspector.getDatabases).toBeDefined(); @@ -376,4 +370,4 @@ describe('MySQLAdapter', () => { expect(adapter.getDataSourceType()).toBe(DataSourceType.MySQL); }); }); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/postgresql.int.test.ts b/packages/data-source/src/adapters/postgresql.int.test.ts index 5f7558c50..75a169141 100644 --- a/packages/data-source/src/adapters/postgresql.int.test.ts +++ b/packages/data-source/src/adapters/postgresql.int.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { PostgreSQLAdapter } from './postgresql'; import { DataSourceType } from '../types/credentials'; import type { PostgreSQLCredentials } from '../types/credentials'; +import { PostgreSQLAdapter } from './postgresql'; // Check if PostgreSQL test credentials are available const hasPostgreSQLCredentials = !!( @@ -143,4 +143,4 @@ describe('PostgreSQLAdapter Integration', () => { }, TEST_TIMEOUT ); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/postgresql.test.ts b/packages/data-source/src/adapters/postgresql.test.ts index c208650bd..8e7f6dcad 100644 --- a/packages/data-source/src/adapters/postgresql.test.ts +++ b/packages/data-source/src/adapters/postgresql.test.ts @@ -1,8 +1,8 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; import { Client } from 'pg'; -import { PostgreSQLAdapter } from './postgresql'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { DataSourceType } from '../types/credentials'; import type { PostgreSQLCredentials } from '../types/credentials'; +import { PostgreSQLAdapter } from './postgresql'; // Create mock client instance const mockClient = { @@ -94,9 +94,7 @@ describe('PostgreSQLAdapter', () => { password: 'testpass', } as any; - await expect(adapter.initialize(credentials)).rejects.toThrow( - 'Database name is required' - ); + await expect(adapter.initialize(credentials)).rejects.toThrow('Database name is required'); }); it('should use default port when not specified', async () => { @@ -239,7 +237,7 @@ describe('PostgreSQLAdapter', () => { expect(mockClient.query).toHaveBeenCalledWith('SET statement_timeout = 60000'); expect(mockClient.query).toHaveBeenCalledWith('SELECT * FROM users', undefined); - + expect(result).toEqual({ rows: [{ id: 1, name: 'Test' }], rowCount: 1, @@ -356,7 +354,7 @@ describe('PostgreSQLAdapter', () => { }; await adapter.initialize(credentials); - + mockClient.query.mockResolvedValueOnce({ rows: [{ result: 1 }] }); const result = await adapter.testConnection(); @@ -375,7 +373,7 @@ describe('PostgreSQLAdapter', () => { }; await adapter.initialize(credentials); - + mockClient.query.mockRejectedValueOnce(new Error('Connection test failed')); const result = await adapter.testConnection(); @@ -408,7 +406,7 @@ describe('PostgreSQLAdapter', () => { }; await adapter.initialize(credentials); - + mockClient.end.mockRejectedValueOnce(new Error('Close failed')); // Should not throw @@ -427,9 +425,9 @@ describe('PostgreSQLAdapter', () => { }; await adapter.initialize(credentials); - + const introspector = adapter.introspect(); - + // Just verify it returns an introspector with the correct interface expect(introspector).toBeDefined(); expect(introspector.getDatabases).toBeDefined(); @@ -450,4 +448,4 @@ describe('PostgreSQLAdapter', () => { expect(adapter.getDataSourceType()).toBe(DataSourceType.PostgreSQL); }); }); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/redshift.int.test.ts b/packages/data-source/src/adapters/redshift.int.test.ts index 845c26995..b47765855 100644 --- a/packages/data-source/src/adapters/redshift.int.test.ts +++ b/packages/data-source/src/adapters/redshift.int.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { RedshiftAdapter } from './redshift'; import { DataSourceType } from '../types/credentials'; import type { RedshiftCredentials } from '../types/credentials'; +import { RedshiftAdapter } from './redshift'; // Check if Redshift test credentials are available const hasRedshiftCredentials = !!( @@ -139,4 +139,4 @@ describe('RedshiftAdapter Integration', () => { }, TEST_TIMEOUT ); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/redshift.test.ts b/packages/data-source/src/adapters/redshift.test.ts index 3c50aa7be..0f6c286a2 100644 --- a/packages/data-source/src/adapters/redshift.test.ts +++ b/packages/data-source/src/adapters/redshift.test.ts @@ -1,8 +1,8 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; import { Client } from 'pg'; -import { RedshiftAdapter } from './redshift'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { DataSourceType } from '../types/credentials'; import type { RedshiftCredentials } from '../types/credentials'; +import { RedshiftAdapter } from './redshift'; // Mock pg-cursor vi.mock('pg-cursor'); @@ -195,7 +195,7 @@ describe('RedshiftAdapter', () => { expect(mockClient.query).toHaveBeenCalledWith('SET statement_timeout = 60000'); expect(mockClient.query).toHaveBeenCalledWith('SELECT * FROM users', undefined); - + expect(result).toEqual({ rows: [{ id: 1, name: 'Test' }], rowCount: 1, @@ -233,10 +233,8 @@ describe('RedshiftAdapter', () => { }), close: vi.fn((callback) => callback(null)), _result: { - fields: [ - { name: 'id', dataTypeID: 23, dataTypeSize: 4 } - ] - } + fields: [{ name: 'id', dataTypeID: 23, dataTypeSize: 4 }], + }, }; // Mock the SET statement_timeout call @@ -258,10 +256,8 @@ describe('RedshiftAdapter', () => { }), close: vi.fn((callback) => callback(null)), _result: { - fields: [ - { name: 'id', dataTypeID: 23, dataTypeSize: 4 } - ] - } + fields: [{ name: 'id', dataTypeID: 23, dataTypeSize: 4 }], + }, }; // Mock the SET statement_timeout call @@ -359,7 +355,7 @@ describe('RedshiftAdapter', () => { }; await adapter.initialize(credentials); - + mockClient.query.mockResolvedValueOnce({ rows: [{ result: 1 }] }); const result = await adapter.testConnection(); @@ -378,7 +374,7 @@ describe('RedshiftAdapter', () => { }; await adapter.initialize(credentials); - + mockClient.query.mockRejectedValueOnce(new Error('Connection test failed')); const result = await adapter.testConnection(); @@ -411,7 +407,7 @@ describe('RedshiftAdapter', () => { }; await adapter.initialize(credentials); - + mockClient.end.mockRejectedValueOnce(new Error('Close failed')); // Should not throw @@ -430,9 +426,9 @@ describe('RedshiftAdapter', () => { }; await adapter.initialize(credentials); - + const introspector = adapter.introspect(); - + // Just verify it returns an introspector with the correct interface expect(introspector).toBeDefined(); expect(introspector.getDatabases).toBeDefined(); @@ -453,4 +449,4 @@ describe('RedshiftAdapter', () => { expect(adapter.getDataSourceType()).toBe(DataSourceType.Redshift); }); }); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/snowflake-memory-protection.int.test.ts b/packages/data-source/src/adapters/snowflake-memory-protection.int.test.ts index a6a6c90a2..e3f30b596 100644 --- a/packages/data-source/src/adapters/snowflake-memory-protection.int.test.ts +++ b/packages/data-source/src/adapters/snowflake-memory-protection.int.test.ts @@ -1,8 +1,7 @@ import { afterEach, beforeEach, describe, expect } from 'vitest'; -import { SnowflakeAdapter } from './snowflake'; import { DataSourceType } from '../types/credentials'; import type { SnowflakeCredentials } from '../types/credentials'; - +import { SnowflakeAdapter } from './snowflake'; const testWithCredentials = skipIfNoCredentials('snowflake'); diff --git a/packages/data-source/src/adapters/snowflake.int.test.ts b/packages/data-source/src/adapters/snowflake.int.test.ts index 71f29af42..309f585f3 100644 --- a/packages/data-source/src/adapters/snowflake.int.test.ts +++ b/packages/data-source/src/adapters/snowflake.int.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { SnowflakeAdapter } from './snowflake'; import { DataSourceType } from '../types/credentials'; import type { SnowflakeCredentials } from '../types/credentials'; +import { SnowflakeAdapter } from './snowflake'; // Check if Snowflake test credentials are available const hasSnowflakeCredentials = !!( @@ -144,4 +144,4 @@ describe('SnowflakeAdapter Integration', () => { }, TEST_TIMEOUT ); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/snowflake.test.ts b/packages/data-source/src/adapters/snowflake.test.ts index dd236c9f0..239089a9c 100644 --- a/packages/data-source/src/adapters/snowflake.test.ts +++ b/packages/data-source/src/adapters/snowflake.test.ts @@ -1,25 +1,24 @@ +import snowflake from 'snowflake-sdk'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { SnowflakeAdapter } from './snowflake'; import { DataSourceType } from '../types/credentials'; import type { SnowflakeCredentials } from '../types/credentials'; -import snowflake from 'snowflake-sdk'; +import { SnowflakeAdapter } from './snowflake'; // Get mocked snowflake-sdk vi.mock('snowflake-sdk'); const mockedSnowflake = vi.mocked(snowflake); - describe('SnowflakeAdapter', () => { let adapter: SnowflakeAdapter; let mockConnection: any; beforeEach(async () => { vi.clearAllMocks(); - + await SnowflakeAdapter.cleanup(); - + adapter = new SnowflakeAdapter(); - + // Create mock connection for each test mockConnection = { connect: vi.fn((cb) => cb()), @@ -27,7 +26,7 @@ describe('SnowflakeAdapter', () => { destroy: vi.fn((cb) => cb()), isUp: vi.fn().mockReturnValue(false), // Return false to prevent warm connection reuse }; - + mockedSnowflake.createConnection = vi.fn().mockReturnValue(mockConnection); mockedSnowflake.configure = vi.fn(); }); @@ -127,7 +126,6 @@ describe('SnowflakeAdapter', () => { 'Invalid credentials type. Expected snowflake, got postgres' ); }); - }); describe('query execution', () => { @@ -143,9 +141,9 @@ describe('SnowflakeAdapter', () => { beforeEach(async () => { // Reset all mocks before each test vi.clearAllMocks(); - + await SnowflakeAdapter.cleanup(); - + // Create fresh adapter and connection for each test adapter = new SnowflakeAdapter(); mockConnection = { @@ -155,19 +153,35 @@ describe('SnowflakeAdapter', () => { isUp: vi.fn().mockReturnValue(false), }; mockedSnowflake.createConnection = vi.fn().mockReturnValue(mockConnection); - + await adapter.initialize(credentials); }); it('should execute simple query without parameters', async () => { const mockRows = [{ ID: 1, NAME: 'Test' }]; mockConnection.execute.mockImplementation(({ complete }) => { - complete(null, { - getColumns: () => [ - { getName: () => 'ID', getType: () => 'NUMBER', isNullable: () => false, getScale: () => 0, getPrecision: () => 38 }, - { getName: () => 'NAME', getType: () => 'TEXT', isNullable: () => true, getScale: () => 0, getPrecision: () => 0 }, - ], - }, mockRows); + complete( + null, + { + getColumns: () => [ + { + getName: () => 'ID', + getType: () => 'NUMBER', + isNullable: () => false, + getScale: () => 0, + getPrecision: () => 38, + }, + { + getName: () => 'NAME', + getType: () => 'TEXT', + isNullable: () => true, + getScale: () => 0, + getPrecision: () => 0, + }, + ], + }, + mockRows + ); }); const result = await adapter.query('SELECT * FROM users'); @@ -177,7 +191,7 @@ describe('SnowflakeAdapter', () => { binds: undefined, complete: expect.any(Function), }); - + expect(result).toEqual({ rows: mockRows, rowCount: 1, @@ -192,11 +206,21 @@ describe('SnowflakeAdapter', () => { it('should execute parameterized query', async () => { const mockRows = [{ ID: 1 }]; mockConnection.execute.mockImplementation(({ complete }) => { - complete(null, { - getColumns: () => [ - { getName: () => 'ID', getType: () => 'NUMBER', isNullable: () => false, getScale: () => 0, getPrecision: () => 38 }, - ], - }, mockRows); + complete( + null, + { + getColumns: () => [ + { + getName: () => 'ID', + getType: () => 'NUMBER', + isNullable: () => false, + getScale: () => 0, + getPrecision: () => 38, + }, + ], + }, + mockRows + ); }); const result = await adapter.query('SELECT * FROM users WHERE id = ?', [1]); @@ -206,13 +230,23 @@ describe('SnowflakeAdapter', () => { it('should handle maxRows limit', async () => { const mockRows = Array.from({ length: 15 }, (_, i) => ({ ID: i + 1 })); - + mockConnection.execute.mockImplementation(({ complete }) => { - complete(null, { - getColumns: () => [ - { getName: () => 'ID', getType: () => 'NUMBER', isNullable: () => false, getScale: () => 0, getPrecision: () => 38 }, - ], - }, mockRows); + complete( + null, + { + getColumns: () => [ + { + getName: () => 'ID', + getType: () => 'NUMBER', + isNullable: () => false, + getScale: () => 0, + getPrecision: () => 38, + }, + ], + }, + mockRows + ); }); const result = await adapter.query('SELECT * FROM users', [], 10); @@ -241,12 +275,28 @@ describe('SnowflakeAdapter', () => { it('should handle empty result sets', async () => { mockConnection.execute.mockImplementation(({ complete }) => { - complete(null, { - getColumns: () => [ - { getName: () => 'ID', getType: () => 'NUMBER', isNullable: () => false, getScale: () => 0, getPrecision: () => 38 }, - { getName: () => 'NAME', getType: () => 'TEXT', isNullable: () => true, getScale: () => 0, getPrecision: () => 0 }, - ], - }, []); + complete( + null, + { + getColumns: () => [ + { + getName: () => 'ID', + getType: () => 'NUMBER', + isNullable: () => false, + getScale: () => 0, + getPrecision: () => 38, + }, + { + getName: () => 'NAME', + getType: () => 'TEXT', + isNullable: () => true, + getScale: () => 0, + getPrecision: () => 0, + }, + ], + }, + [] + ); }); const result = await adapter.query('SELECT * FROM users WHERE 1=0'); @@ -258,7 +308,7 @@ describe('SnowflakeAdapter', () => { it('should handle query timeout', async () => { vi.useFakeTimers(); - + mockConnection.execute.mockImplementation(() => { // Never call complete to simulate timeout }); @@ -269,7 +319,7 @@ describe('SnowflakeAdapter', () => { vi.advanceTimersByTime(150); await expect(queryPromise).rejects.toThrow(/timeout/i); - + vi.useRealTimers(); }); }); @@ -278,9 +328,9 @@ describe('SnowflakeAdapter', () => { beforeEach(async () => { // Reset all mocks before each test vi.clearAllMocks(); - + await SnowflakeAdapter.cleanup(); - + // Create fresh adapter and connection for each test adapter = new SnowflakeAdapter(); mockConnection = { @@ -303,11 +353,15 @@ describe('SnowflakeAdapter', () => { }; await adapter.initialize(credentials); - + mockConnection.execute.mockImplementation(({ complete }) => { - complete(null, { - getColumns: () => [], - }, [{ TEST: 1 }]); + complete( + null, + { + getColumns: () => [], + }, + [{ TEST: 1 }] + ); }); const result = await adapter.testConnection(); @@ -331,7 +385,7 @@ describe('SnowflakeAdapter', () => { }; await adapter.initialize(credentials); - + mockConnection.execute.mockImplementation(({ complete }) => { complete(new Error('Connection test failed')); }); @@ -352,19 +406,19 @@ describe('SnowflakeAdapter', () => { }; await adapter.initialize(credentials); - + const originalDateNow = Date.now; const currentTime = Date.now(); - const oldTime = currentTime - (6 * 60 * 1000); // 6 minutes ago (older than CONNECTION_REUSE_TIME of 5 minutes) - + const oldTime = currentTime - 6 * 60 * 1000; // 6 minutes ago (older than CONNECTION_REUSE_TIME of 5 minutes) + (adapter as any).lastActivity = oldTime; - + Date.now = vi.fn().mockReturnValue(currentTime); - + await adapter.close(); expect(mockConnection.destroy).toHaveBeenCalled(); - + Date.now = originalDateNow; }); @@ -379,15 +433,15 @@ describe('SnowflakeAdapter', () => { }; await adapter.initialize(credentials); - + const originalDateNow = Date.now; Date.now = vi.fn().mockReturnValue(1000000000); // Old timestamp to force destroy - + mockConnection.destroy.mockImplementation((cb) => cb(new Error('Close failed'))); // Should not throw await adapter.close(); - + Date.now = originalDateNow; }); }); @@ -396,9 +450,9 @@ describe('SnowflakeAdapter', () => { beforeEach(async () => { // Reset all mocks before each test vi.clearAllMocks(); - + await SnowflakeAdapter.cleanup(); - + // Create fresh adapter and connection for each test adapter = new SnowflakeAdapter(); mockConnection = { @@ -421,9 +475,9 @@ describe('SnowflakeAdapter', () => { }; await adapter.initialize(credentials); - + const introspector = adapter.introspect(); - + // Just verify it returns an introspector with the correct interface expect(introspector).toBeDefined(); expect(introspector.getDatabases).toBeDefined(); @@ -449,9 +503,9 @@ describe('SnowflakeAdapter', () => { beforeEach(async () => { // Reset all mocks before each test vi.clearAllMocks(); - + await SnowflakeAdapter.cleanup(); - + // Create fresh adapter and connection for each test adapter = new SnowflakeAdapter(); mockConnection = { @@ -474,9 +528,9 @@ describe('SnowflakeAdapter', () => { }; await adapter.initialize(credentials); - + const stats = adapter.getConnectionStats(); - + expect(stats).toHaveProperty('connected', true); expect(stats).toHaveProperty('credentialKey'); expect(stats).toHaveProperty('lastActivity'); diff --git a/packages/data-source/src/adapters/sqlserver.int.test.ts b/packages/data-source/src/adapters/sqlserver.int.test.ts index 336c2a903..550ce207f 100644 --- a/packages/data-source/src/adapters/sqlserver.int.test.ts +++ b/packages/data-source/src/adapters/sqlserver.int.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { SQLServerAdapter } from './sqlserver'; import { DataSourceType } from '../types/credentials'; import type { SQLServerCredentials } from '../types/credentials'; +import { SQLServerAdapter } from './sqlserver'; // Check if SQLServer test credentials are available const hasSQLServerCredentials = !!( @@ -139,4 +139,4 @@ describe('SQLServerAdapter Integration', () => { }, TEST_TIMEOUT ); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/sqlserver.test.ts b/packages/data-source/src/adapters/sqlserver.test.ts index 97b308c88..036cf9554 100644 --- a/packages/data-source/src/adapters/sqlserver.test.ts +++ b/packages/data-source/src/adapters/sqlserver.test.ts @@ -1,8 +1,8 @@ +import sql from 'mssql'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { SQLServerAdapter } from './sqlserver'; import { DataSourceType } from '../types/credentials'; import type { SQLServerCredentials } from '../types/credentials'; -import sql from 'mssql'; +import { SQLServerAdapter } from './sqlserver'; // Mock mssql module vi.mock('mssql'); @@ -16,23 +16,23 @@ describe('SQLServerAdapter', () => { beforeEach(() => { vi.clearAllMocks(); adapter = new SQLServerAdapter(); - + // Create mock request for each test mockRequest = { query: vi.fn(), input: vi.fn().mockReturnThis(), }; - + // Create mock pool for each test mockPool = { request: vi.fn().mockReturnValue(mockRequest), close: vi.fn().mockResolvedValue(undefined), connect: vi.fn().mockResolvedValue(undefined), }; - + // Mock the ConnectionPool constructor mockedSql.ConnectionPool = vi.fn().mockReturnValue(mockPool); - + // Mock SQL Server data types mockedSql.NVarChar = vi.fn(); mockedSql.Int = vi.fn(); @@ -170,7 +170,7 @@ describe('SQLServerAdapter', () => { const result = await adapter.query('SELECT * FROM users'); expect(mockRequest.query).toHaveBeenCalledWith('SELECT * FROM users'); - + expect(result).toEqual({ rows: [{ id: 1, name: 'Test' }], rowCount: 1, @@ -202,22 +202,23 @@ describe('SQLServerAdapter', () => { let recordsetCallback: any; let rowCallback: any; let doneCallback: any; - + mockRequest.on = vi.fn((event, callback) => { if (event === 'recordset') recordsetCallback = callback; if (event === 'row') rowCallback = callback; if (event === 'done') doneCallback = callback; - if (event === 'error') {} // Ignore error callback + if (event === 'error') { + } // Ignore error callback }); - + mockRequest.pause = vi.fn(); mockRequest.cancel = vi.fn(); - + mockRequest.query.mockImplementation(() => { // Simulate async behavior setTimeout(() => { recordsetCallback?.({ id: { name: 'id', type: () => ({ name: 'int' }) } }); - rows.forEach(row => rowCallback?.(row)); + rows.forEach((row) => rowCallback?.(row)); doneCallback?.(); }, 0); }); @@ -236,22 +237,23 @@ describe('SQLServerAdapter', () => { let recordsetCallback: any; let rowCallback: any; let doneCallback: any; - + mockRequest.on = vi.fn((event, callback) => { if (event === 'recordset') recordsetCallback = callback; if (event === 'row') rowCallback = callback; if (event === 'done') doneCallback = callback; - if (event === 'error') {} // Ignore error callback + if (event === 'error') { + } // Ignore error callback }); - + mockRequest.pause = vi.fn(); mockRequest.cancel = vi.fn(); - + mockRequest.query.mockImplementation(() => { // Simulate async behavior setTimeout(() => { recordsetCallback?.({ id: { name: 'id', type: () => ({ name: 'int' }) } }); - rows.forEach(row => rowCallback?.(row)); + rows.forEach((row) => rowCallback?.(row)); doneCallback?.(); }, 0); }); @@ -332,22 +334,23 @@ describe('SQLServerAdapter', () => { let recordsetCallback: any; let rowCallback: any; let doneCallback: any; - + mockRequest.on = vi.fn((event, callback) => { if (event === 'recordset') recordsetCallback = callback; if (event === 'row') rowCallback = callback; if (event === 'done') doneCallback = callback; - if (event === 'error') {} // Ignore error callback + if (event === 'error') { + } // Ignore error callback }); - + mockRequest.pause = vi.fn(); mockRequest.cancel = vi.fn(); - + mockRequest.query.mockImplementation(() => { // Simulate async behavior setTimeout(() => { recordsetCallback?.({ id: { name: 'id', type: () => ({ name: 'int' }) } }); - rows.forEach(row => rowCallback?.(row)); + rows.forEach((row) => rowCallback?.(row)); doneCallback?.(); }, 0); }); @@ -417,7 +420,7 @@ describe('SQLServerAdapter', () => { }; await adapter.initialize(credentials); - + mockRequest.query.mockResolvedValueOnce({ recordset: [{ test: 1 }], }); @@ -438,7 +441,7 @@ describe('SQLServerAdapter', () => { }; await adapter.initialize(credentials); - + mockRequest.query.mockRejectedValueOnce(new Error('Connection test failed')); const result = await adapter.testConnection(); @@ -471,7 +474,7 @@ describe('SQLServerAdapter', () => { }; await adapter.initialize(credentials); - + mockPool.close.mockRejectedValueOnce(new Error('Close failed')); // Should not throw @@ -490,9 +493,9 @@ describe('SQLServerAdapter', () => { }; await adapter.initialize(credentials); - + const introspector = adapter.introspect(); - + // Just verify it returns an introspector with the correct interface expect(introspector).toBeDefined(); expect(introspector.getDatabases).toBeDefined(); @@ -513,4 +516,4 @@ describe('SQLServerAdapter', () => { expect(adapter.getDataSourceType()).toBe(DataSourceType.SQLServer); }); }); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/adapters/timeout.test.ts b/packages/data-source/src/adapters/timeout.test.ts index af173169d..df4fc4507 100644 --- a/packages/data-source/src/adapters/timeout.test.ts +++ b/packages/data-source/src/adapters/timeout.test.ts @@ -1,10 +1,4 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { BigQueryAdapter } from './bigquery'; -import { MySQLAdapter } from './mysql'; -import { PostgreSQLAdapter } from './postgresql'; -import { RedshiftAdapter } from './redshift'; -import { SnowflakeAdapter } from './snowflake'; -import { SQLServerAdapter } from './sqlserver'; import type { BigQueryCredentials, MySQLCredentials, @@ -13,6 +7,12 @@ import type { SQLServerCredentials, SnowflakeCredentials, } from '../types/credentials'; +import { BigQueryAdapter } from './bigquery'; +import { MySQLAdapter } from './mysql'; +import { PostgreSQLAdapter } from './postgresql'; +import { RedshiftAdapter } from './redshift'; +import { SnowflakeAdapter } from './snowflake'; +import { SQLServerAdapter } from './sqlserver'; // Mock all external dependencies vi.mock('@google-cloud/bigquery'); @@ -72,7 +72,7 @@ describe.skip('Adapter Timeout Tests', () => { describe('PostgreSQLAdapter timeout', () => { it('should timeout after specified duration', async () => { vi.useFakeTimers(); - + const mockClient = { connect: vi.fn().mockResolvedValue(undefined), query: vi.fn( @@ -153,7 +153,7 @@ describe.skip('Adapter Timeout Tests', () => { describe('MySQLAdapter timeout', () => { it('should timeout after specified duration', async () => { vi.useFakeTimers(); - + const mockConnection = { execute: vi.fn( () => @@ -195,7 +195,7 @@ describe.skip('Adapter Timeout Tests', () => { describe('SnowflakeAdapter timeout', () => { it('should timeout after specified duration', async () => { vi.useFakeTimers(); - + const mockConnection = { connect: vi.fn((callback: (err: unknown) => void) => callback(null)), execute: vi.fn(() => { @@ -234,7 +234,7 @@ describe.skip('Adapter Timeout Tests', () => { describe('SqlServerAdapter timeout', () => { it('should timeout after specified duration', async () => { vi.useFakeTimers(); - + const mockRequest = { query: vi.fn( () => @@ -280,7 +280,7 @@ describe.skip('Adapter Timeout Tests', () => { describe('Default timeout behavior', () => { it('should use default timeout when none specified', async () => { vi.useFakeTimers(); - + const mockConnection = { execute: vi.fn( () => @@ -319,4 +319,4 @@ describe.skip('Adapter Timeout Tests', () => { await expect(queryPromise).rejects.toThrow(/timeout/i); }); }); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/config/timeouts.ts b/packages/data-source/src/config/timeouts.ts index 1aecb1102..a3c2d8332 100644 --- a/packages/data-source/src/config/timeouts.ts +++ b/packages/data-source/src/config/timeouts.ts @@ -88,4 +88,4 @@ export function getRetryDelay(attemptNumber: number): number { // Return the last delay in the array as fallback const lastDelay = TIMEOUT_CONFIG.retry.delays[TIMEOUT_CONFIG.retry.delays.length - 1]; return lastDelay !== undefined ? lastDelay : 6000; // Fallback to 6s if something goes wrong -} \ No newline at end of file +} diff --git a/packages/data-source/src/data-source.int.test.ts b/packages/data-source/src/data-source.int.test.ts index f5f19b4b7..11f7485ba 100644 --- a/packages/data-source/src/data-source.int.test.ts +++ b/packages/data-source/src/data-source.int.test.ts @@ -9,13 +9,13 @@ const TEST_TIMEOUT = 5000; // Check if credentials are available const hasPostgreSQLCredentials = !!( - process.env.TEST_POSTGRES_DATABASE && - process.env.TEST_POSTGRES_USERNAME && + process.env.TEST_POSTGRES_DATABASE && + process.env.TEST_POSTGRES_USERNAME && process.env.TEST_POSTGRES_PASSWORD ); const hasMySQLCredentials = !!( - process.env.TEST_MYSQL_DATABASE && - process.env.TEST_MYSQL_USERNAME && + process.env.TEST_MYSQL_DATABASE && + process.env.TEST_MYSQL_USERNAME && process.env.TEST_MYSQL_PASSWORD ); @@ -303,9 +303,9 @@ describe('DataSource Integration', () => { it('should throw error when querying non-existent data source', async () => { dataSource = new DataSource({ dataSources: [] }); - await expect( - dataSource.query('SELECT 1', [], { warehouse: 'non-existent' }) - ).rejects.toThrow('Data source non-existent not found'); + await expect(dataSource.query('SELECT 1', [], { warehouse: 'non-existent' })).rejects.toThrow( + 'Data source non-existent not found' + ); }); }); }); @@ -337,4 +337,4 @@ describe('QueryRouter Backward Compatibility', () => { const result = await router.query('SELECT 1 as test'); expect(result.data.rows[0]).toEqual({ test: 1 }); }); -}); \ No newline at end of file +}); diff --git a/packages/data-source/src/introspection/bigquery.int.test.ts b/packages/data-source/src/introspection/bigquery.int.test.ts index 7cc956cff..280ba8c08 100644 --- a/packages/data-source/src/introspection/bigquery.int.test.ts +++ b/packages/data-source/src/introspection/bigquery.int.test.ts @@ -1,9 +1,9 @@ import { afterEach, describe, expect } from 'vitest'; import { DataSource } from '../data-source'; import type { DataSourceConfig } from '../data-source'; +import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; import { DataSourceType } from '../types/credentials'; import type { BigQueryCredentials } from '../types/credentials'; -import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; function createBigQueryCredentials(): BigQueryCredentials { if (!testConfig.bigquery.project_id) { diff --git a/packages/data-source/src/introspection/multi-datasource.int.test.ts b/packages/data-source/src/introspection/multi-datasource.int.test.ts index 32ea95d60..c669ca52d 100644 --- a/packages/data-source/src/introspection/multi-datasource.int.test.ts +++ b/packages/data-source/src/introspection/multi-datasource.int.test.ts @@ -1,6 +1,7 @@ import { afterEach, describe, expect, it } from 'vitest'; import { DataSource } from '../data-source'; import type { DataSourceConfig } from '../data-source'; +import { TEST_TIMEOUT, hasCredentials, testConfig } from '../setup'; import { DataSourceType } from '../types/credentials'; import type { BigQueryCredentials, @@ -8,7 +9,6 @@ import type { PostgreSQLCredentials, SnowflakeCredentials, } from '../types/credentials'; -import { TEST_TIMEOUT, hasCredentials, testConfig } from '../setup'; // Helper functions to create credentials for each data source type function createPostgreSQLCredentials(): PostgreSQLCredentials { diff --git a/packages/data-source/src/introspection/mysql.int.test.ts b/packages/data-source/src/introspection/mysql.int.test.ts index 5145f7ceb..452d7628a 100644 --- a/packages/data-source/src/introspection/mysql.int.test.ts +++ b/packages/data-source/src/introspection/mysql.int.test.ts @@ -1,10 +1,10 @@ import { afterEach, describe, expect } from 'vitest'; import { DataSource } from '../data-source'; import type { DataSourceConfig } from '../data-source'; +import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; import { DataSourceType } from '../types/credentials'; import type { MySQLCredentials } from '../types/credentials'; import type { ColumnStatistics, Table, TableStatistics } from '../types/introspection'; -import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; function createMySQLCredentials(): MySQLCredentials { if (!testConfig.mysql.database || !testConfig.mysql.username || !testConfig.mysql.password) { diff --git a/packages/data-source/src/introspection/postgresql.int.test.ts b/packages/data-source/src/introspection/postgresql.int.test.ts index 98fa75fdf..d5663e05c 100644 --- a/packages/data-source/src/introspection/postgresql.int.test.ts +++ b/packages/data-source/src/introspection/postgresql.int.test.ts @@ -1,10 +1,10 @@ import { afterEach, describe, expect } from 'vitest'; import { DataSource } from '../data-source'; import type { DataSourceConfig } from '../data-source'; +import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; import { DataSourceType } from '../types/credentials'; import type { PostgreSQLCredentials } from '../types/credentials'; import type { ColumnStatistics, Table, TableStatistics } from '../types/introspection'; -import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; function createPostgreSQLCredentials(): PostgreSQLCredentials { if ( diff --git a/packages/data-source/src/introspection/redshift.int.test.ts b/packages/data-source/src/introspection/redshift.int.test.ts index e9670efa9..fb4556c75 100644 --- a/packages/data-source/src/introspection/redshift.int.test.ts +++ b/packages/data-source/src/introspection/redshift.int.test.ts @@ -1,9 +1,9 @@ import { afterEach, describe, expect } from 'vitest'; import { DataSource } from '../data-source'; import type { DataSourceConfig } from '../data-source'; +import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; import { DataSourceType } from '../types/credentials'; import type { RedshiftCredentials } from '../types/credentials'; -import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; function createRedshiftCredentials(): RedshiftCredentials { if ( diff --git a/packages/data-source/src/introspection/snowflake.int.test.ts b/packages/data-source/src/introspection/snowflake.int.test.ts index 225ba89bd..5aa2bfaae 100644 --- a/packages/data-source/src/introspection/snowflake.int.test.ts +++ b/packages/data-source/src/introspection/snowflake.int.test.ts @@ -1,10 +1,10 @@ import { afterEach, describe, expect } from 'vitest'; import { DataSource } from '../data-source'; import type { DataSourceConfig } from '../data-source'; +import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; import { DataSourceType } from '../types/credentials'; import type { SnowflakeCredentials } from '../types/credentials'; import type { ColumnStatistics, Table, TableStatistics } from '../types/introspection'; -import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; function createSnowflakeCredentials(): SnowflakeCredentials { if ( diff --git a/packages/data-source/src/introspection/sqlserver.int.test.ts b/packages/data-source/src/introspection/sqlserver.int.test.ts index 1952caa23..b737ebb43 100644 --- a/packages/data-source/src/introspection/sqlserver.int.test.ts +++ b/packages/data-source/src/introspection/sqlserver.int.test.ts @@ -1,9 +1,9 @@ import { afterEach, describe, expect } from 'vitest'; import { DataSource } from '../data-source'; import type { DataSourceConfig } from '../data-source'; +import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; import { DataSourceType } from '../types/credentials'; import type { SQLServerCredentials } from '../types/credentials'; -import { TEST_TIMEOUT, skipIfNoCredentials, testConfig } from '../setup'; function createSQLServerCredentials(): SQLServerCredentials { if ( diff --git a/packages/server-shared/src/chats/chat.types.test.ts b/packages/server-shared/src/chats/chat.types.test.ts index 70091fb66..f664ee832 100644 --- a/packages/server-shared/src/chats/chat.types.test.ts +++ b/packages/server-shared/src/chats/chat.types.test.ts @@ -1,11 +1,11 @@ import { describe, expect, it } from 'vitest'; +import { ShareIndividualSchema } from '../share'; import { AssetPermissionRoleSchema, ChatCreateHandlerRequestSchema, ChatCreateRequestSchema, ChatWithMessagesSchema, } from './chat.types'; -import { ShareIndividualSchema } from '../share'; describe('AssetPermissionRoleSchema', () => { it('should accept valid role values', () => { diff --git a/packages/test-utils/src/database/dataSources/createTestDataSource.test.ts b/packages/test-utils/src/database/dataSources/createTestDataSource.test.ts index 2c0afd616..f7f4c6f20 100644 --- a/packages/test-utils/src/database/dataSources/createTestDataSource.test.ts +++ b/packages/test-utils/src/database/dataSources/createTestDataSource.test.ts @@ -17,8 +17,8 @@ describe('Organization Data Source Helper - Unit Tests', () => { beforeEach(async () => { await setupTestEnvironment(); vi.clearAllMocks(); - - const createTestDataSourceMock = await vi.importMock('./createTestDataSource') as any; + + const createTestDataSourceMock = (await vi.importMock('./createTestDataSource')) as any; mockCreateTestDataSource = createTestDataSourceMock.createTestDataSource; }); @@ -32,7 +32,7 @@ describe('Organization Data Source Helper - Unit Tests', () => { organizationId: 'test-org-id', dataSourceType: 'postgresql', }; - + const mockResult = { dataSourceId: 'test-data-source-id', dataSourceSyntax: 'postgresql', @@ -43,7 +43,7 @@ describe('Organization Data Source Helper - Unit Tests', () => { const { getOrganizationDataSource } = await import('@buster/database'); const { createTestDataSource } = await import('./createTestDataSource'); - + const { dataSourceId, organizationId, dataSourceType } = await createTestDataSource(); const input = { organizationId }; const result = await getOrganizationDataSource(input); @@ -53,7 +53,9 @@ describe('Organization Data Source Helper - Unit Tests', () => { }); test('getOrganizationDataSource validates UUID input', async () => { - mockGetOrganizationDataSource.mockRejectedValue(new Error('Organization ID must be a valid UUID')); + mockGetOrganizationDataSource.mockRejectedValue( + new Error('Organization ID must be a valid UUID') + ); const { getOrganizationDataSource } = await import('@buster/database'); const input = { organizationId: 'invalid-uuid' }; @@ -64,7 +66,9 @@ describe('Organization Data Source Helper - Unit Tests', () => { }); test('getOrganizationDataSource throws for non-existent organization', async () => { - mockGetOrganizationDataSource.mockRejectedValue(new Error('No data sources found for organization')); + mockGetOrganizationDataSource.mockRejectedValue( + new Error('No data sources found for organization') + ); const { getOrganizationDataSource } = await import('@buster/database'); const input = { @@ -84,11 +88,15 @@ describe('Organization Data Source Helper - Unit Tests', () => { }; mockCreateTestDataSource.mockResolvedValue(mockDataSource); - mockGetOrganizationDataSource.mockRejectedValue(new Error('Multiple data sources found for organization. Data source selection is not available yet - please contact support if you need to work with multiple data sources.')); + mockGetOrganizationDataSource.mockRejectedValue( + new Error( + 'Multiple data sources found for organization. Data source selection is not available yet - please contact support if you need to work with multiple data sources.' + ) + ); const { getOrganizationDataSource } = await import('@buster/database'); const { createTestDataSource } = await import('./createTestDataSource'); - + const { organizationId } = await createTestDataSource(); await createTestDataSource({ organizationId }); diff --git a/packages/test-utils/src/database/messageUpdates.test.ts b/packages/test-utils/src/database/messageUpdates.test.ts index 9b1e06bdf..925f55496 100644 --- a/packages/test-utils/src/database/messageUpdates.test.ts +++ b/packages/test-utils/src/database/messageUpdates.test.ts @@ -24,14 +24,16 @@ describe('Message Updates Test Helpers - Unit Tests', () => { chatId: 'test-chat-id', organizationId: 'test-org-id', }; - + mockCreateTestMessageWithContext.mockResolvedValue(mockResult); - - const { createTestMessageWithContext } = await import('./messages/createTestMessageWithContext'); + + const { createTestMessageWithContext } = await import( + './messages/createTestMessageWithContext' + ); const result = await createTestMessageWithContext({ reasoning: { steps: ['Initial step'], conclusion: 'Test conclusion' }, }); - + expect(result).toEqual(mockResult); expect(mockCreateTestMessageWithContext).toHaveBeenCalledWith({ reasoning: { steps: ['Initial step'], conclusion: 'Test conclusion' }, @@ -45,14 +47,16 @@ describe('Message Updates Test Helpers - Unit Tests', () => { chatId: 'test-chat-id', organizationId: 'test-org-id', }; - + mockCreateTestMessageWithContext.mockResolvedValue(mockResult); - - const { createTestMessageWithContext } = await import('./messages/createTestMessageWithContext'); + + const { createTestMessageWithContext } = await import( + './messages/createTestMessageWithContext' + ); const result = await createTestMessageWithContext({ responseMessages: { content: 'Streaming response', metadata: { streaming: true } }, }); - + expect(result).toEqual(mockResult); expect(mockCreateTestMessageWithContext).toHaveBeenCalledWith({ responseMessages: { content: 'Streaming response', metadata: { streaming: true } }, @@ -64,22 +68,24 @@ describe('Message Updates Test Helpers - Unit Tests', () => { { role: 'user', content: 'Hello' }, { role: 'assistant', content: 'Hi there' }, ]; - + const mockResult = { messageId: 'test-message-id', userId: 'test-user-id', chatId: 'test-chat-id', organizationId: 'test-org-id', }; - + mockCreateTestMessageWithContext.mockResolvedValue(mockResult); - - const { createTestMessageWithContext } = await import('./messages/createTestMessageWithContext'); + + const { createTestMessageWithContext } = await import( + './messages/createTestMessageWithContext' + ); const result = await createTestMessageWithContext({ rawLlmMessages, requestMessage: 'Hello', }); - + expect(result).toEqual(mockResult); expect(mockCreateTestMessageWithContext).toHaveBeenCalledWith({ rawLlmMessages, diff --git a/packages/test-utils/src/database/messages/createTestMessage.test.ts b/packages/test-utils/src/database/messages/createTestMessage.test.ts index 716e96634..09f965382 100644 --- a/packages/test-utils/src/database/messages/createTestMessage.test.ts +++ b/packages/test-utils/src/database/messages/createTestMessage.test.ts @@ -28,12 +28,12 @@ describe('createTestMessage', () => { beforeEach(async () => { await setupTestEnvironment(); vi.clearAllMocks(); - - const dbMock = await vi.importMock('@buster/database') as any; + + const dbMock = (await vi.importMock('@buster/database')) as any; mockValues = dbMock.mockValues; mockInsert = dbMock.mockInsert; mockMessages = dbMock.mockMessages; - + mockValues.mockResolvedValue(undefined); }); @@ -86,7 +86,6 @@ describe('createTestMessage', () => { expect(messageId).toBeDefined(); - expect(mockValues).toHaveBeenCalledWith( expect.objectContaining({ id: messageId, @@ -116,7 +115,6 @@ describe('createTestMessage', () => { expect(messageId).toBeDefined(); - expect(mockValues).toHaveBeenCalledWith( expect.objectContaining({ id: messageId, @@ -180,7 +178,6 @@ describe('createTestMessage', () => { await createTestMessage(chatId, createdBy, options); - expect(mockValues).toHaveBeenCalledWith( expect.objectContaining({ feedback: 'Test feedback', diff --git a/packages/test-utils/src/database/messages/createTestMessageWithContext.test.ts b/packages/test-utils/src/database/messages/createTestMessageWithContext.test.ts index 7eb26146d..e9fc4dd13 100644 --- a/packages/test-utils/src/database/messages/createTestMessageWithContext.test.ts +++ b/packages/test-utils/src/database/messages/createTestMessageWithContext.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; -import { createTestChat } from '../chats/createTestChat'; import { cleanupTestEnvironment, setupTestEnvironment } from '../../envHelpers/env-helpers'; +import { createTestChat } from '../chats/createTestChat'; import { type CreateTestMessageOptions, createTestMessage } from './createTestMessage'; import { createTestMessageWithContext } from './createTestMessageWithContext'; diff --git a/packages/test-utils/src/database/messages/messageContext.test.ts b/packages/test-utils/src/database/messages/messageContext.test.ts index a783b89fa..1edcf2bd1 100644 --- a/packages/test-utils/src/database/messages/messageContext.test.ts +++ b/packages/test-utils/src/database/messages/messageContext.test.ts @@ -24,12 +24,12 @@ describe('Message Context Helper - Unit Tests', () => { chatId: 'test-chat-id', organizationId: 'test-org-id', }; - + mockCreateTestMessageWithContext.mockResolvedValue(mockResult); - + const { createTestMessageWithContext } = await import('./createTestMessageWithContext'); const result = await createTestMessageWithContext(); - + expect(result).toEqual(mockResult); expect(mockCreateTestMessageWithContext).toHaveBeenCalledWith(); }); @@ -40,19 +40,19 @@ describe('Message Context Helper - Unit Tests', () => { requestMessage: 'Custom request', isCompleted: false, }; - + const mockResult = { messageId: 'test-message-id', userId: 'test-user-id', chatId: 'test-chat-id', organizationId: 'test-org-id', }; - + mockCreateTestMessageWithContext.mockResolvedValue(mockResult); - + const { createTestMessageWithContext } = await import('./createTestMessageWithContext'); const result = await createTestMessageWithContext(options); - + expect(result).toEqual(mockResult); expect(mockCreateTestMessageWithContext).toHaveBeenCalledWith(options); }); diff --git a/packages/test-utils/src/database/updateMessageFields.test.ts b/packages/test-utils/src/database/updateMessageFields.test.ts index 6e32cc164..e7dba4b57 100644 --- a/packages/test-utils/src/database/updateMessageFields.test.ts +++ b/packages/test-utils/src/database/updateMessageFields.test.ts @@ -24,12 +24,14 @@ describe('updateMessageFields - Unit Tests', () => { chatId: 'test-chat-id', organizationId: 'test-org-id', }; - + mockCreateTestMessageWithContext.mockResolvedValue(mockResult); - - const { createTestMessageWithContext } = await import('./messages/createTestMessageWithContext'); + + const { createTestMessageWithContext } = await import( + './messages/createTestMessageWithContext' + ); const result = await createTestMessageWithContext(); - + expect(result).toEqual(mockResult); expect(mockCreateTestMessageWithContext).toHaveBeenCalledWith(); }); @@ -40,19 +42,21 @@ describe('updateMessageFields - Unit Tests', () => { requestMessage: 'Initial request', isCompleted: false, }; - + const mockResult = { messageId: 'test-message-id', userId: 'test-user-id', chatId: 'test-chat-id', organizationId: 'test-org-id', }; - + mockCreateTestMessageWithContext.mockResolvedValue(mockResult); - - const { createTestMessageWithContext } = await import('./messages/createTestMessageWithContext'); + + const { createTestMessageWithContext } = await import( + './messages/createTestMessageWithContext' + ); const result = await createTestMessageWithContext(options); - + expect(result).toEqual(mockResult); expect(mockCreateTestMessageWithContext).toHaveBeenCalledWith(options); }); diff --git a/packages/test-utils/src/envHelpers/env-helpers.test.ts b/packages/test-utils/src/envHelpers/env-helpers.test.ts index 1cecf7ae4..f3ab051c8 100644 --- a/packages/test-utils/src/envHelpers/env-helpers.test.ts +++ b/packages/test-utils/src/envHelpers/env-helpers.test.ts @@ -1,11 +1,16 @@ import { describe, expect, it, vi } from 'vitest'; -import { type TestEnvironment, cleanupTestEnvironment, setupTestEnvironment, withTestEnv } from './env-helpers'; +import { + type TestEnvironment, + cleanupTestEnvironment, + setupTestEnvironment, + withTestEnv, +} from './env-helpers'; describe('env-helpers.ts - Unit Tests', () => { describe('setupTestEnvironment', () => { it('should return TestEnvironment object with cleanup and reset functions', async () => { const env = await setupTestEnvironment(); - + expect(env).toHaveProperty('cleanup'); expect(env).toHaveProperty('reset'); expect(typeof env.cleanup).toBe('function'); @@ -14,11 +19,11 @@ describe('env-helpers.ts - Unit Tests', () => { it('should set NODE_ENV to test', async () => { const originalEnv = process.env.NODE_ENV; - + await setupTestEnvironment(); - + expect(process.env.NODE_ENV).toBe('test'); - + if (originalEnv !== undefined) { process.env.NODE_ENV = originalEnv; } else { @@ -29,14 +34,14 @@ describe('env-helpers.ts - Unit Tests', () => { it('should store original environment variables', async () => { const originalValue = process.env.TEST_VAR; process.env.TEST_VAR = 'original-value'; - + const env = await setupTestEnvironment(); process.env.TEST_VAR = 'modified-value'; - + await env.cleanup(); - + expect(process.env.TEST_VAR).toBe('original-value'); - + if (originalValue === undefined) { delete process.env.TEST_VAR; } else { @@ -47,19 +52,19 @@ describe('env-helpers.ts - Unit Tests', () => { it('should restore environment on cleanup', async () => { const originalNodeEnv = process.env.NODE_ENV; const originalCustomVar = process.env.CUSTOM_TEST_VAR; - + process.env.CUSTOM_TEST_VAR = 'initial-value'; - + const env = await setupTestEnvironment(); - + process.env.NODE_ENV = 'production'; process.env.CUSTOM_TEST_VAR = 'changed-value'; - + await env.cleanup(); - + expect(process.env.NODE_ENV).toBe(originalNodeEnv); expect(process.env.CUSTOM_TEST_VAR).toBe('initial-value'); - + if (originalCustomVar === undefined) { delete process.env.CUSTOM_TEST_VAR; } @@ -67,13 +72,13 @@ describe('env-helpers.ts - Unit Tests', () => { it('should reset to test state on reset', async () => { const env = await setupTestEnvironment(); - + process.env.NODE_ENV = 'production'; - + await env.reset(); - + expect(process.env.NODE_ENV).toBe('test'); - + await env.cleanup(); }); }); @@ -82,9 +87,9 @@ describe('env-helpers.ts - Unit Tests', () => { it('should wrap test function with environment setup and cleanup', async () => { const testFn = vi.fn().mockResolvedValue('test-result'); const wrappedFn = withTestEnv(testFn); - + const result = await wrappedFn(); - + expect(result).toBe('test-result'); expect(testFn).toHaveBeenCalledTimes(1); }); @@ -92,17 +97,17 @@ describe('env-helpers.ts - Unit Tests', () => { it('should set up test environment before running test', async () => { const originalNodeEnv = process.env.NODE_ENV; process.env.NODE_ENV = 'production'; - + const testFn = vi.fn().mockImplementation(() => { expect(process.env.NODE_ENV).toBe('test'); return Promise.resolve(); }); - + const wrappedFn = withTestEnv(testFn); await wrappedFn(); - + expect(testFn).toHaveBeenCalled(); - + if (originalNodeEnv !== undefined) { process.env.NODE_ENV = originalNodeEnv; } else { @@ -113,27 +118,27 @@ describe('env-helpers.ts - Unit Tests', () => { it('should clean up environment after test completion', async () => { const originalNodeEnv = process.env.NODE_ENV; const originalCustomVar = process.env.CUSTOM_VAR; - + process.env.NODE_ENV = 'production'; process.env.CUSTOM_VAR = 'original'; - + const testFn = vi.fn().mockImplementation(() => { process.env.CUSTOM_VAR = 'modified'; return Promise.resolve(); }); - + const wrappedFn = withTestEnv(testFn); await wrappedFn(); - + expect(process.env.NODE_ENV).toBe('production'); expect(process.env.CUSTOM_VAR).toBe('original'); - + if (originalNodeEnv !== undefined) { process.env.NODE_ENV = originalNodeEnv; } else { delete process.env.NODE_ENV; } - + if (originalCustomVar === undefined) { delete process.env.CUSTOM_VAR; } @@ -142,14 +147,14 @@ describe('env-helpers.ts - Unit Tests', () => { it('should clean up environment even if test throws', async () => { const originalNodeEnv = process.env.NODE_ENV; process.env.NODE_ENV = 'production'; - + const testFn = vi.fn().mockRejectedValue(new Error('Test error')); const wrappedFn = withTestEnv(testFn); - + await expect(wrappedFn()).rejects.toThrow('Test error'); - + expect(process.env.NODE_ENV).toBe('production'); - + if (originalNodeEnv !== undefined) { process.env.NODE_ENV = originalNodeEnv; } else { @@ -161,9 +166,9 @@ describe('env-helpers.ts - Unit Tests', () => { const expectedResult = { data: 'test', count: 42 }; const testFn = vi.fn().mockResolvedValue(expectedResult); const wrappedFn = withTestEnv(testFn); - + const result = await wrappedFn(); - + expect(result).toEqual(expectedResult); }); }); @@ -171,9 +176,9 @@ describe('env-helpers.ts - Unit Tests', () => { describe('cleanupTestEnvironment', () => { it('should be a function that returns a Promise', () => { expect(typeof cleanupTestEnvironment).toBe('function'); - + const result = cleanupTestEnvironment(); - + expect(result).toBeInstanceOf(Promise); }); @@ -183,9 +188,9 @@ describe('env-helpers.ts - Unit Tests', () => { it('should be a no-op function', async () => { const originalEnv = { ...process.env }; - + await cleanupTestEnvironment(); - + expect(process.env).toEqual(originalEnv); }); }); @@ -193,19 +198,19 @@ describe('env-helpers.ts - Unit Tests', () => { describe('TestEnvironment interface', () => { it('should have correct structure', async () => { const env: TestEnvironment = await setupTestEnvironment(); - + expect(env).toHaveProperty('cleanup'); expect(env).toHaveProperty('reset'); - + expect(typeof env.cleanup).toBe('function'); expect(typeof env.reset).toBe('function'); - + const cleanupResult = env.cleanup(); const resetResult = env.reset(); - + expect(cleanupResult).toBeInstanceOf(Promise); expect(resetResult).toBeInstanceOf(Promise); - + await cleanupResult; await resetResult; }); diff --git a/packages/test-utils/src/envHelpers/env-helpers.ts b/packages/test-utils/src/envHelpers/env-helpers.ts index 1641e4c7a..bd06f5742 100644 --- a/packages/test-utils/src/envHelpers/env-helpers.ts +++ b/packages/test-utils/src/envHelpers/env-helpers.ts @@ -30,12 +30,14 @@ export async function setupTestEnvironment(): Promise { export function withTestEnv(testFn: () => Promise): () => Promise { return async () => { const originalEnv = { ...process.env }; + + // biome-ignore lint/correctness/noUnusedVariables: const env = await setupTestEnvironment(); try { return await testFn(); } finally { // Restore original environment - Object.keys(process.env).forEach(key => { + Object.keys(process.env).forEach((key) => { if (!(key in originalEnv)) { delete process.env[key]; } diff --git a/packages/test-utils/src/mock-helpers.test.ts b/packages/test-utils/src/mock-helpers.test.ts index ff3f19cbe..4927290b2 100644 --- a/packages/test-utils/src/mock-helpers.test.ts +++ b/packages/test-utils/src/mock-helpers.test.ts @@ -5,7 +5,7 @@ describe('mock-helpers.ts - Unit Tests', () => { describe('createMockFunction', () => { it('should create a mock function without implementation', () => { const mockFn = createMockFunction(); - + expect(vi.isMockFunction(mockFn)).toBe(true); expect(mockFn).toHaveBeenCalledTimes(0); }); @@ -13,7 +13,7 @@ describe('mock-helpers.ts - Unit Tests', () => { it('should create a mock function with implementation', () => { const implementation = (x: number, y: number) => x + y; const mockFn = createMockFunction(implementation); - + expect(vi.isMockFunction(mockFn)).toBe(true); expect(mockFn(2, 3)).toBe(5); expect(mockFn).toHaveBeenCalledWith(2, 3); @@ -22,7 +22,7 @@ describe('mock-helpers.ts - Unit Tests', () => { it('should allow mock function to be configured', () => { const mockFn = createMockFunction(); mockFn.mockReturnValue('test-value'); - + expect(mockFn()).toBe('test-value'); expect(mockFn).toHaveBeenCalledTimes(1); }); @@ -34,19 +34,19 @@ describe('mock-helpers.ts - Unit Tests', () => { const originalError = console.error; const originalWarn = console.warn; const originalInfo = console.info; - + const { mocks, restore } = mockConsole(); - + expect(vi.isMockFunction(console.log)).toBe(true); expect(vi.isMockFunction(console.error)).toBe(true); expect(vi.isMockFunction(console.warn)).toBe(true); expect(vi.isMockFunction(console.info)).toBe(true); - + expect(mocks.log).toBe(console.log); expect(mocks.error).toBe(console.error); expect(mocks.warn).toBe(console.warn); expect(mocks.info).toBe(console.info); - + restore(); expect(console.log).toBe(originalLog); expect(console.error).toBe(originalError); @@ -56,28 +56,28 @@ describe('mock-helpers.ts - Unit Tests', () => { it('should track console method calls', () => { const { mocks, restore } = mockConsole(); - + console.log('test message'); console.error('error message'); console.warn('warning message'); console.info('info message'); - + expect(mocks.log).toHaveBeenCalledWith('test message'); expect(mocks.error).toHaveBeenCalledWith('error message'); expect(mocks.warn).toHaveBeenCalledWith('warning message'); expect(mocks.info).toHaveBeenCalledWith('info message'); - + restore(); }); it('should restore original console methods', () => { const originalLog = console.log; const { restore } = mockConsole(); - + expect(console.log).not.toBe(originalLog); - + restore(); - + expect(console.log).toBe(originalLog); }); }); @@ -86,55 +86,55 @@ describe('mock-helpers.ts - Unit Tests', () => { it('should mock Date constructor with string input', () => { const fixedDateString = '2024-01-01T00:00:00.000Z'; const { restore } = createMockDate(fixedDateString); - + const mockDate = new Date(); expect(mockDate.toISOString()).toBe(fixedDateString); - + restore(); }); it('should mock Date constructor with Date input', () => { const fixedDate = new Date('2024-06-15T12:30:00.000Z'); const { restore } = createMockDate(fixedDate); - + const mockDate = new Date(); expect(mockDate.getTime()).toBe(fixedDate.getTime()); - + restore(); }); it('should mock Date.now()', () => { const fixedDate = new Date('2024-03-10T08:45:00.000Z'); const { restore } = createMockDate(fixedDate); - + expect(Date.now()).toBe(fixedDate.getTime()); - + restore(); }); it('should restore original Date constructor', () => { const originalDate = Date; const { restore } = createMockDate('2024-01-01'); - + expect(Date).not.toBe(originalDate); - + restore(); - + expect(Date).toBe(originalDate); }); it('should work with multiple mock dates', () => { const date1 = '2024-01-01T00:00:00.000Z'; const date2 = '2024-12-31T23:59:59.999Z'; - + const mock1 = createMockDate(date1); expect(new Date().toISOString()).toBe(date1); - + mock1.restore(); - + const mock2 = createMockDate(date2); expect(new Date().toISOString()).toBe(date2); - + mock2.restore(); }); }); diff --git a/packages/test-utils/src/mock-helpers.ts b/packages/test-utils/src/mock-helpers.ts index 9516784da..cc6eb07e5 100644 --- a/packages/test-utils/src/mock-helpers.ts +++ b/packages/test-utils/src/mock-helpers.ts @@ -12,7 +12,7 @@ export function mockConsole() { warn: console.warn, info: console.info, }; - + const mockedMethods = { log: vi.fn(), error: vi.fn(),