Files
supabase/apps/studio/components/interfaces/Platform/Webhooks/PlatformWebhooksEndpointDetails.test.tsx
Danny White 6b6598994f chore(studio): add pagination to webhook deliveries table (#43847)
## What kind of change does this PR introduce?

UI update.

## What is the current behavior?

The webhook endpoint details view showed all mock deliveries in a single
table with a Studio-specific sortable header treatment, no pagination,
and uneven row heights when the retry action was absent.

## What is the new behavior?

Moves the deliveries table onto TanStack table state, adopts the shared
`TableHeadSort` header UI, keeps the existing delivery search, and adds
simple previous/next pagination controls at the bottom. The mock
deliveries are expanded so pagination and sorting can be exercised in
both organisation and project flows, and the actions column now reserves
a consistent button footprint so every row keeps the same minimum
height.

| Before | After |
| --- | --- |
| <img width="1728" height="997" alt="Webhooks Settings Chisel Toolshed
Supabase-A4712323-6FD9-471B-B1F4-234B20686018"
src="https://github.com/user-attachments/assets/2745e5fd-1ef7-4f3a-872c-1fd8d10dce41"
/> | <img width="1728" height="997" alt="Webhooks Settings Chisel
Toolshed Supabase-D482241B-F324-4EA2-9B89-133AD5E10F17"
src="https://github.com/user-attachments/assets/5bfcefd8-cb58-46c0-a863-dcf80e4da4a3"
/> |

## Additional context

This keeps the view on the Data Table path now, while aligning the
sortable headers with the design-system table pattern instead of the
older Studio-local `DataTableColumnHeader` helper.
2026-03-27 10:03:56 +11:00

142 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import type { ComponentProps } from 'react'
import { describe, expect, it, vi } from 'vitest'
import { PLATFORM_WEBHOOKS_MOCK_DATA } from './PlatformWebhooks.mock'
import { PlatformWebhooksEndpointDetails } from './PlatformWebhooksEndpointDetails'
vi.mock('components/ui/DataTable/DataTableColumn/DataTableColumnStatusCode', () => ({
DataTableColumnStatusCode: ({ value }: { value: number }) => <span>{value}</span>,
}))
vi.mock('components/ui/ButtonTooltip', () => ({
ButtonTooltip: ({
icon,
children,
size: _size,
tooltip: _tooltip,
type: _type,
...props
}: any) => (
<button type="button" {...props}>
{icon}
{children}
</button>
),
}))
vi.mock('ui-patterns', async () => {
const actual = await vi.importActual<typeof import('ui-patterns')>('ui-patterns')
return {
...actual,
TimestampInfo: ({ utcTimestamp, className }: { utcTimestamp: string; className?: string }) => (
<span className={className}>{utcTimestamp}</span>
),
}
})
describe('PlatformWebhooksEndpointDetails', () => {
const selectedEndpoint = PLATFORM_WEBHOOKS_MOCK_DATA.organization.endpoints[0]
const allDeliveries = PLATFORM_WEBHOOKS_MOCK_DATA.organization.deliveries.filter(
(delivery) => delivery.endpointId === selectedEndpoint.id
)
const renderComponent = (
props?: Partial<ComponentProps<typeof PlatformWebhooksEndpointDetails>>
) =>
render(
<PlatformWebhooksEndpointDetails
deliverySearch=""
filteredDeliveries={allDeliveries}
selectedEndpoint={selectedEndpoint}
onDeliverySearchChange={vi.fn()}
onOpenDelivery={vi.fn()}
onRetryDelivery={vi.fn()}
{...props}
/>
)
it('renders paginated deliveries with previous and next controls', async () => {
const user = userEvent.setup()
renderComponent()
expect(screen.getByText('Showing 1 to 5 of 12 deliveries')).toBeInTheDocument()
expect(screen.queryByText('organization.member_removed')).not.toBeInTheDocument()
await user.click(screen.getByLabelText('Next page'))
expect(screen.getByText('Showing 6 to 10 of 12 deliveries')).toBeInTheDocument()
expect(screen.getByText('organization.member_removed')).toBeInTheDocument()
await user.click(screen.getByLabelText('Previous page'))
expect(screen.getByText('Showing 1 to 5 of 12 deliveries')).toBeInTheDocument()
expect(screen.queryByText('organization.member_removed')).not.toBeInTheDocument()
})
it('sorts deliveries by event type from the header', async () => {
const user = userEvent.setup()
renderComponent()
await user.click(screen.getByRole('button', { name: 'Event type' }))
expect(screen.getAllByRole('row')[1]).toHaveTextContent('organization.member_invited')
await user.click(screen.getByRole('button', { name: 'Event type' }))
expect(screen.getAllByRole('row')[1]).toHaveTextContent('project.updated')
})
it('resets to the first page when the delivery search changes', async () => {
const user = userEvent.setup()
const projectDeliveries = allDeliveries.filter((delivery) =>
delivery.eventType.includes('project')
)
const { rerender } = renderComponent()
await user.click(screen.getByLabelText('Next page'))
expect(screen.getByText('Showing 6 to 10 of 12 deliveries')).toBeInTheDocument()
rerender(
<PlatformWebhooksEndpointDetails
deliverySearch="project"
filteredDeliveries={projectDeliveries}
selectedEndpoint={selectedEndpoint}
onDeliverySearchChange={vi.fn()}
onOpenDelivery={vi.fn()}
onRetryDelivery={vi.fn()}
/>
)
await waitFor(() => {
expect(screen.getByText('Showing 1 to 5 of 8 deliveries')).toBeInTheDocument()
})
})
it('retries a failed delivery without opening the delivery row', async () => {
const user = userEvent.setup()
const onOpenDelivery = vi.fn()
const onRetryDelivery = vi.fn()
renderComponent({ onOpenDelivery, onRetryDelivery })
await user.click(screen.getByLabelText('Retry org-delivery-2'))
expect(onRetryDelivery).toHaveBeenCalledWith('org-delivery-2')
expect(onOpenDelivery).not.toHaveBeenCalled()
})
it('renders a zero response code instead of the placeholder', () => {
renderComponent({
filteredDeliveries: [{ ...allDeliveries[0], id: 'org-delivery-zero', responseCode: 0 }],
})
expect(screen.getByText('0')).toBeInTheDocument()
expect(screen.queryByText('')).not.toBeInTheDocument()
})
})