chore: add unit test for regression of webhooks (#44409)

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

We had some bugs where webhooks were not able to be turned on for
projects. This is to ensure that doesn't happen again

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Added UI tests for integration overview and installation flows: verify
action enablement/disablement (aria-disabled and visual opacity)
depending on required extensions, ensure the "Install integration"
button is disabled when no installation command or required extensions
are missing, and confirm the installation command is invoked (without
executing SQL) when appropriate.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
Ali WaseemandJoshen Lim authored and GitHub committed 2026-04-01 11:52:30 -06:00
1 parent 38d012a232
commit 91a8d59e43
2 files changed
+208

No files matched your search

@@ -0,0 +1,85 @@
import { screen } from '@testing-library/dom'
import { mockAnimationsApi } from 'jsdom-testing-mocks'
import { customRender } from 'tests/lib/custom-render'
import { routerMock } from 'tests/lib/route-mock'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { IntegrationOverviewTab } from './IntegrationOverviewTab'
mockAnimationsApi()
vi.mock('../Landing/Integrations.constants', () => ({
INTEGRATIONS: [
{
id: 'test-integration',
name: 'Test Integration',
requiredExtensions: ['pg_net'],
},
],
}))
vi.mock('framer-motion', async (importOriginal) => {
const actual = (await importOriginal()) as any
return {
...actual,
motion: {
...actual.motion,
div: ({ children, ...props }: any) => <div {...props}>{children}</div>,
},
}
})
const mockExtensions = vi.fn()
vi.mock('data/database-extensions/database-extensions-query', () => ({
useDatabaseExtensionsQuery: () => ({ data: mockExtensions() }),
}))
vi.mock('@/hooks/misc/useSelectedProject', () => ({
useSelectedProjectQuery: () => ({
data: { ref: 'default', connectionString: 'postgres://localhost' },
}),
useIsOrioleDb: () => false,
}))
vi.mock('common', async (importOriginal) => {
const actual = (await importOriginal()) as any
return {
...actual,
useParams: () => ({ id: 'test-integration', ref: 'default' }),
}
})
vi.mock('./MarkdownContent', () => ({
MarkdownContent: () => null,
}))
describe('IntegrationOverviewTab', () => {
beforeEach(() => {
routerMock.setCurrentUrl('/project/default/integrations/test-integration/overview')
mockExtensions.mockReturnValue([
{ name: 'pg_net', installed_version: null, default_version: '0.6.0' },
])
})
it('does not disable actions when hideRequiredExtensionsSection is true and extensions are uninstalled', () => {
customRender(
<IntegrationOverviewTab
hideRequiredExtensionsSection
actions={<button>Enable webhooks</button>}
/>
)
const actionsArea = screen.getByText('Enable webhooks').closest('[aria-disabled]')
expect(actionsArea).toHaveAttribute('aria-disabled', 'false')
expect(actionsArea).not.toHaveClass('opacity-25')
})
it('disables actions when extensions are uninstalled and hideRequiredExtensionsSection is false', () => {
customRender(<IntegrationOverviewTab actions={<button>Enable integration</button>} />)
const actionsArea = screen.getByText('Enable integration').closest('[aria-disabled]')
expect(actionsArea).toHaveAttribute('aria-disabled', 'true')
expect(actionsArea).toHaveClass('opacity-25')
})
})
@@ -0,0 +1,123 @@
import { screen, waitFor } from '@testing-library/dom'
import userEvent from '@testing-library/user-event'
import { mockAnimationsApi } from 'jsdom-testing-mocks'
import { customRender } from 'tests/lib/custom-render'
import { routerMock } from 'tests/lib/route-mock'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { IntegrationDefinition } from '../../Landing/Integrations.constants'
import { InstallIntegrationSheet } from './InstallIntegrationSheet'
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: () => 'CREATE EXTENSION IF NOT EXISTS pg_net;',
getExtensionDefaultSchema: () => 'extensions',
}))
const createIntegration = (overrides: Partial<IntegrationDefinition> = {}): 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(
<InstallIntegrationSheet
integration={createIntegration({
installationCommand: vi.fn().mockResolvedValue(undefined),
})}
/>
)
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(
<InstallIntegrationSheet
integration={createIntegration({ installationCommand: undefined })}
/>
)
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(
<InstallIntegrationSheet
integration={createIntegration({ installationCommand: mockCommand })}
/>
)
await userEvent.click(screen.getByRole('button', { name: 'Install integration' }))
await userEvent.click(getInstallButton())
await waitFor(() => {
expect(mockCommand).toHaveBeenCalledWith({ ref: 'default' })
})
expect(mockExecuteSql).not.toHaveBeenCalled()
})
})