mirror of
https://github.com/supabase/supabase.git
synced 2026-10-17 15:19:08 +03:00
## Problem The pipeline wizard in #49243 needs publication, initial sync and replication settings together on its data step. ## Solution Compose `PipelineDataSection` from the existing controls and use it in preview-enabled creation. It includes the publication selector, initial-sync controls and data advanced settings, including BigQuery table layout. This preserves the grouping from #51570. Preview off and editing keep the existing layout. Validation and creation behaviour stay the same; no wizard routing is added. Stacked on #51570. ## Review instructions 1. Open the [Pipelines preview](https://studio-staging-git-dnywh-featpipeline-data-section-supabase.vercel.app/dashboard/project/_/database/pipelines), select a test project with Pipelines enabled and go to **Database → Pipelines**. Enable **Pipeline creation wizard** in Feature Previews, then click **Add pipeline**. Confirm **Data** follows **Destination connection**, with publication and initial sync above its **Advanced settings**. 2. Select a publication and change the initial-sync option. For selected-table options, confirm the publication tables are available. Click **New publication** in the publication selector and confirm the existing creation panel opens, then cancel it. 3. Expand **Advanced settings** under **Data**. Confirm replication settings appear, plus table layout for BigQuery, without connection pool size, staleness or role. Change **Batch wait time**, collapse and reopen the accordion, and confirm the value remains. Check desktop and phone widths. Cancel and discard changes; no credentials or pipeline creation are needed. 4. Turn the preview off and reopen **Add pipeline**. Confirm the original layout remains. With the preview on, edit an existing pipeline and confirm its original layout also remains.
120 lines
4.3 KiB
TypeScript
120 lines
4.3 KiB
TypeScript
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
|
import type { components } from 'api-types'
|
|
import { mockAnimationsApi } from 'jsdom-testing-mocks'
|
|
import { HttpResponse } from 'msw'
|
|
import { useForm } from 'react-hook-form'
|
|
import { Form } from 'ui'
|
|
import { describe, expect, it, vi } from 'vitest'
|
|
|
|
import type { DestinationPanelSchemaType } from '../DestinationPanel/DestinationForm/DestinationForm.schema'
|
|
import type { DestinationType } from '../DestinationPanel/DestinationPanel.types'
|
|
import { PipelineDataSection } from './PipelineDataSection'
|
|
import { customRender } from '@/tests/lib/custom-render'
|
|
import { addAPIMock } from '@/tests/lib/msw'
|
|
|
|
mockAnimationsApi()
|
|
type ReplicationSourcesResponse = components['schemas']['SourcesResponse_Output']
|
|
type PublicationDetailsResponse = components['schemas']['PublicationDetailsResponse_Output']
|
|
type PublicationNamesResponse = components['schemas']['ReadPublicationsResponse_Output']
|
|
|
|
const mockSources: ReplicationSourcesResponse = {
|
|
sources: [
|
|
{
|
|
id: 1,
|
|
name: 'default',
|
|
tenant_id: 'tenant',
|
|
config: { host: 'db.internal', name: 'main-db', port: 5432, username: 'etl_user' },
|
|
},
|
|
],
|
|
}
|
|
|
|
const mockPublicationDetails = (publishViaPartitionRoot: boolean): PublicationDetailsResponse => ({
|
|
name: 'analytics',
|
|
config: {
|
|
type: 'tables',
|
|
tables: [],
|
|
operations: ['insert', 'update', 'delete', 'truncate'],
|
|
publish_via_partition_root: publishViaPartitionRoot,
|
|
},
|
|
tables: [],
|
|
})
|
|
|
|
const mockPublicationRequests = (publishViaPartitionRoot: boolean) => {
|
|
addAPIMock({
|
|
method: 'get',
|
|
path: '/platform/replication/:ref/sources',
|
|
response: () => HttpResponse.json<ReplicationSourcesResponse>(mockSources),
|
|
})
|
|
addAPIMock({
|
|
method: 'get',
|
|
path: '/platform/replication/v2/:ref/sources/:source_id/publications',
|
|
response: () =>
|
|
HttpResponse.json<PublicationNamesResponse>({
|
|
publications: [{ name: 'analytics' }],
|
|
}),
|
|
})
|
|
addAPIMock({
|
|
method: 'get',
|
|
path: '/platform/replication/v2/:ref/sources/:source_id/publications/:publication_name',
|
|
response: () =>
|
|
HttpResponse.json<PublicationDetailsResponse>(
|
|
mockPublicationDetails(publishViaPartitionRoot)
|
|
),
|
|
})
|
|
}
|
|
|
|
const TestSection = ({ type }: { type: DestinationType }) => {
|
|
const form = useForm<DestinationPanelSchemaType>({
|
|
defaultValues: {
|
|
publicationName: 'analytics',
|
|
tableSyncCopyMode: 'include_all_tables',
|
|
tableSyncCopyTableIds: [],
|
|
maxFillMs: 500,
|
|
maxTableSyncWorkers: 4,
|
|
maxCopyConnectionsPerTable: 1,
|
|
invalidatedSlotBehavior: 'error',
|
|
tableOptions: [],
|
|
},
|
|
})
|
|
return (
|
|
<Form {...form}>
|
|
<PipelineDataSection type={type} form={form} onSelectNewPublication={vi.fn()} />
|
|
</Form>
|
|
)
|
|
}
|
|
|
|
describe('PipelineDataSection', () => {
|
|
it.each<DestinationType>(['BigQuery', 'DuckLake', 'Snowflake', 'ClickHouse', 'Analytics Bucket'])(
|
|
'groups %s publication, initial sync and replication settings without connection fields',
|
|
async (type) => {
|
|
mockPublicationRequests(false)
|
|
customRender(<TestSection type={type} />)
|
|
expect(screen.getByRole('region', { name: 'Data' })).toBeInTheDocument()
|
|
expect(screen.getByText('Initial sync')).toBeInTheDocument()
|
|
await waitFor(() =>
|
|
expect(screen.getByRole('status')).toHaveTextContent(
|
|
'Each partition is replicated separately.'
|
|
)
|
|
)
|
|
fireEvent.click(screen.getByRole('button', { name: /Advanced settings/ }))
|
|
expect(screen.getByLabelText('Batch wait time')).toHaveValue(500)
|
|
expect(screen.getByLabelText('Table sync workers')).toHaveValue(4)
|
|
expect(screen.queryByText('Table layout') !== null).toBe(type === 'BigQuery')
|
|
for (const label of [
|
|
'Pipeline name',
|
|
'Pipeline region',
|
|
'Connection pool size',
|
|
'Maximum staleness',
|
|
'Pool size',
|
|
'Role',
|
|
]) {
|
|
expect(screen.queryByText(label)).not.toBeInTheDocument()
|
|
}
|
|
fireEvent.change(screen.getByLabelText('Batch wait time'), { target: { value: '750' } })
|
|
fireEvent.click(screen.getByRole('button', { name: /Advanced settings/ }))
|
|
fireEvent.click(screen.getByRole('button', { name: /Advanced settings/ }))
|
|
expect(screen.getByLabelText('Batch wait time')).toHaveValue(750)
|
|
}
|
|
)
|
|
})
|