import { safeSql } from '@supabase/pg-meta' import { fireEvent, screen, waitFor } from '@testing-library/dom' import userEvent from '@testing-library/user-event' import { mockAnimationsApi } from 'jsdom-testing-mocks' import { beforeEach, describe, expect, it, vi } from 'vitest' import { IntegrationDefinition } from '../../Landing/Integrations.constants' import { InstallIntegrationSheet } from './InstallIntegrationSheet/InstallIntegrationSheet' import { customRender } from '@/tests/lib/custom-render' import { routerMock } from '@/tests/lib/route-mock' mockAnimationsApi() vi.mock('@/hooks/misc/useSelectedProject', () => ({ useSelectedProjectQuery: () => ({ data: { ref: 'default', connectionString: 'postgres://localhost' }, }), })) vi.mock('@/hooks/useProtectedSchemas', () => ({ useProtectedSchemas: () => ({ data: [] }), })) const mockExtensions = vi.fn() vi.mock('@/data/database-extensions/database-extensions-query', () => ({ useDatabaseExtensionsQuery: () => ({ data: mockExtensions(), isSuccess: true }), })) vi.mock('@/data/database/schemas-query', () => ({ useSchemasQuery: () => ({ data: [{ id: 1, name: 'public' }] }), })) const mockExecuteSql = vi.fn() vi.mock('@/data/sql/execute-sql-mutation', () => ({ useExecuteSqlMutation: () => ({ mutateAsync: mockExecuteSql }), })) vi.mock('@/data/database-extensions/database-extension-enable-mutation', () => ({ useDatabaseExtensionEnableMutation: () => ({ mutateAsync: vi.fn() }), })) vi.mock('@/components/interfaces/Database/Extensions/Extensions.constants', () => ({ extensionsWithRecommendedSchemas: {}, })) vi.mock('./IntegrationOverviewTabV2.utils', () => ({ getEnableExtensionsSQL: () => safeSql`CREATE EXTENSION IF NOT EXISTS pg_net;`, getExtensionDefaultSchema: () => 'extensions', })) const createIntegration = (overrides: Partial = {}): IntegrationDefinition => ({ id: 'test-integration', type: 'postgres_extension', name: 'Test Integration', requiredExtensions: ['pg_net'], icon: () => null, description: 'Test description', docsUrl: null, author: { name: 'Test', websiteUrl: 'https://test.com' }, navigate: () => null, ...overrides, }) as unknown as any const getInstallButton = () => { const buttons = screen.getAllByRole('button', { name: 'Install integration' }) return buttons[buttons.length - 1] } describe('InstallIntegrationSheet', () => { beforeEach(() => { routerMock.setCurrentUrl('/project/default/integrations/test-integration/overview') mockExecuteSql.mockReset() }) it('install button is disabled when extensions are missing even if installationCommand exists', async () => { mockExtensions.mockReturnValue([]) customRender( ) await userEvent.click(screen.getByRole('button', { name: 'Install integration' })) expect(getInstallButton()).toBeDisabled() }) it('install button is disabled when extensions are missing and no installationCommand', async () => { mockExtensions.mockReturnValue([]) customRender( ) await userEvent.click(screen.getByRole('button', { name: 'Install integration' })) expect(getInstallButton()).toBeDisabled() }) it('uses installationCommand instead of SQL when provided', async () => { mockExtensions.mockReturnValue([ { name: 'pg_net', installed_version: null, default_version: '0.6.0' }, ]) const mockCommand = vi.fn().mockResolvedValue(undefined) customRender( ) await userEvent.click(screen.getByRole('button', { name: 'Install integration' })) // SheetContent renders via a Radix portal, placing the submit button outside // the
in the DOM. jsdom doesn't support the HTML `form` attribute on // buttons, so we submit the form directly instead of clicking the button. const form = document.getElementById('installation-settings')! fireEvent.submit(form) await waitFor(() => { expect(mockCommand).toHaveBeenCalledWith(expect.objectContaining({ ref: 'default' })) }) expect(mockExecuteSql).not.toHaveBeenCalled() }) })