mirror of
https://github.com/supabase/supabase.git
synced 2026-10-15 14:19:11 +03:00
## What
Wires the existing (mocked) Platform Webhooks UI to the real Management
API backend, per FE-3749.
- New `data/platform-webhooks/` query/mutation hooks, calling the real
`/v2/organizations/{slug}/webhooks/...` and
`/v2/projects/{ref}/webhooks/...` endpoints
- Updated `PlatformWebhooks.types.ts` to match the real API contract
(field names, shapes)
- Added a signing secret field to the create-endpoint form (API requires
a user-provided secret, not server-generated like the mock assumed)
- Removed the event-type column from the deliveries table (the real
list-deliveries endpoint doesn't return event type, only the
single-delivery endpoint does)
- Removed `PlatformWebhooks.mock.ts` / `.store.ts` and their tests
## Why
UI was built ~80% against mock data months ago; this closes the gap to a
real, working feature.
## Known open items (not blocking, tracked separately)
- `name` field has no backend storage yet — client-only for now, open
question with Ali/Paweł
- Deliveries table only fetches the backend's default single page — real
server-side pagination not yet wired (see FE-3750)
## Follow-up PR (stacked)
Tests for the new `data/platform-webhooks/` hooks (MSW-based), per the
ticket's own scope split.
## Testing
Manually tested end-to-end against local backend: created/edited/deleted
an endpoint, verified the real signature using webhook.site,
independently recomputed the HMAC and confirmed it matches the
`webhook-signature` header.
Linear: FE-3749
---------
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
import { beforeEach, describe, expect, it } from 'vitest'
|
|
|
|
import {
|
|
clearPendingSigningSecretReveal,
|
|
getPendingSigningSecretReveal,
|
|
resetPendingSigningSecretRevealForTests,
|
|
setPendingSigningSecretReveal,
|
|
shouldHandleEndpointNotFound,
|
|
shouldRedirectFromWebhooks,
|
|
} from './PlatformWebhooksPage.utils'
|
|
|
|
describe('PlatformWebhooksPage.utils', () => {
|
|
const endpointId = '7f2c9d4a-6e31-4d9d-9a1f-2c4b5e6f7081'
|
|
const otherEndpointId = '1a4e8c73-5b29-44af-8c62-9f1d2b3c4d5e'
|
|
const missingEndpointId = '00000000-0000-4000-8000-000000000000'
|
|
|
|
beforeEach(() => {
|
|
resetPendingSigningSecretRevealForTests()
|
|
})
|
|
|
|
it('returns false when endpoint id is absent', () => {
|
|
expect(
|
|
shouldHandleEndpointNotFound({
|
|
endpointId: undefined,
|
|
hasSelectedEndpoint: false,
|
|
pendingCreatedEndpointId: null,
|
|
})
|
|
).toBe(false)
|
|
})
|
|
|
|
it('returns false when endpoint is selected', () => {
|
|
expect(
|
|
shouldHandleEndpointNotFound({
|
|
endpointId,
|
|
hasSelectedEndpoint: true,
|
|
pendingCreatedEndpointId: null,
|
|
})
|
|
).toBe(false)
|
|
})
|
|
|
|
it('returns false while route is transitioning to a newly created endpoint', () => {
|
|
expect(
|
|
shouldHandleEndpointNotFound({
|
|
endpointId,
|
|
hasSelectedEndpoint: false,
|
|
pendingCreatedEndpointId: endpointId,
|
|
})
|
|
).toBe(false)
|
|
})
|
|
|
|
it('returns true for invalid endpoint routes', () => {
|
|
expect(
|
|
shouldHandleEndpointNotFound({
|
|
endpointId: missingEndpointId,
|
|
hasSelectedEndpoint: false,
|
|
pendingCreatedEndpointId: null,
|
|
})
|
|
).toBe(true)
|
|
})
|
|
|
|
describe('shouldRedirectFromWebhooks', () => {
|
|
it('does not redirect while flags are still loading', () => {
|
|
expect(
|
|
shouldRedirectFromWebhooks({ areFlagsReady: false, isScopeReady: true, isEnabled: false })
|
|
).toBe(false)
|
|
})
|
|
|
|
it('does not redirect before route params are populated', () => {
|
|
expect(
|
|
shouldRedirectFromWebhooks({ areFlagsReady: true, isScopeReady: false, isEnabled: false })
|
|
).toBe(false)
|
|
})
|
|
|
|
it('does not redirect when webhooks are enabled', () => {
|
|
expect(
|
|
shouldRedirectFromWebhooks({ areFlagsReady: true, isScopeReady: true, isEnabled: true })
|
|
).toBe(false)
|
|
})
|
|
|
|
it('redirects once ready and webhooks are disabled', () => {
|
|
expect(
|
|
shouldRedirectFromWebhooks({ areFlagsReady: true, isScopeReady: true, isEnabled: false })
|
|
).toBe(true)
|
|
})
|
|
})
|
|
|
|
it('stores and reads pending signing secret reveal for matching endpoint route', () => {
|
|
setPendingSigningSecretReveal('project', {
|
|
endpointId,
|
|
signingSecret: 'whsec_example',
|
|
})
|
|
|
|
expect(getPendingSigningSecretReveal('project', endpointId)).toEqual({
|
|
endpointId,
|
|
signingSecret: 'whsec_example',
|
|
})
|
|
})
|
|
|
|
it('ignores pending signing secret reveal when endpoint route does not match', () => {
|
|
setPendingSigningSecretReveal('project', {
|
|
endpointId,
|
|
signingSecret: 'whsec_example',
|
|
})
|
|
|
|
expect(getPendingSigningSecretReveal('project', otherEndpointId)).toBeNull()
|
|
})
|
|
|
|
it('clears pending signing secret reveal', () => {
|
|
setPendingSigningSecretReveal('project', {
|
|
endpointId,
|
|
signingSecret: 'whsec_example',
|
|
})
|
|
|
|
clearPendingSigningSecretReveal('project')
|
|
|
|
expect(getPendingSigningSecretReveal('project', endpointId)).toBeNull()
|
|
})
|
|
})
|