Files
supabase/apps/studio/components/interfaces/Integrations/Wrappers/Wrappers.utils.test.ts
T
Gildas Garcia 914677ed4b chore: migrate foreign wrapper forms to react-hook-form (#44512)
## Problem

Foreign wrapper forms still use `formik` but we now use
`react-hook-form` everywhere and we'd like to reduce our dependencies.

## Solution

- [x] Write e2e tests for wrappers
- [x] Migrate to `react-hook-form`

## Notes

I tried to cover the 3 cases I identified for foreign wrappers with e2e
tests:
- Add all available tables to a new schema (stripe)
- Add selected tables to a new table (stripe)
- Create dynamic columns (s3 wrapper)

However, they are not exhaustive as I can't test the integration
actually works, only that it was created successfully. Besides, I can't
test the Iceberg wrapper case as it needs actual S3 buckets.

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

* **New Features**
* Enhanced column-type selector with searchable combobox, enum support,
icons, and optional recommendation prompts.

* **Refactor**
* Migrated many wrapper/table/editor forms to a schema-driven form
system with stronger validation, dynamic field arrays, and consistent
form controls.
* Updated input field integration to work with the new form control
model.

* **Bug Fixes**
* Improved handling of missing wrapper/error states during wrapper
loading.

* **Tests**
* Added unit tests for form schemas and end-to-end tests for wrapper
creation flows.

* **Chores**
  * Removed legacy dynamic-columns component.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-09 09:20:27 +02:00

210 lines
6.0 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { SUPABASE_TARGET_SCHEMA_OPTION, WRAPPER_HANDLERS, WRAPPERS } from './Wrappers.constants'
import { Table } from './Wrappers.types'
import {
getEditionFormSchema,
getTableFormSchema,
getWrapperCreationFormSchema,
} from './Wrappers.utils'
const stripe_wrapper = {
name: 'stripe_wrapper',
handlerName: WRAPPER_HANDLERS.STRIPE,
validatorName: 'stripe_fdw_validator',
icon: '',
description: 'Payment processing and subscription management',
extensionName: 'StripeFdw',
label: 'Stripe',
docsUrl: '',
server: {
options: [
{
name: 'api_key_id',
label: 'Stripe Secret Key',
required: true,
encrypted: true,
secureEntry: true,
urlHelper: 'https://stripe.com/docs/keys',
},
{
name: 'api_url',
label: 'Stripe API URL',
defaultValue: 'https://api.stripe.com/v1',
required: false,
encrypted: false,
secureEntry: false,
},
SUPABASE_TARGET_SCHEMA_OPTION,
],
},
tables: [],
}
describe('getWrapperCreationFormSchema', () => {
it('should build a schema that validates tables mode', () => {
const schema = getWrapperCreationFormSchema(stripe_wrapper)
const result = schema.safeParse({ mode: 'tables' })
expect(result.success).toEqual(false)
// Common required field
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'wrapper_name'))
).toBeDefined()
// Table mode specific field
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'tables'))
).toBeDefined()
})
it('should build a schema that validates schema mode', () => {
const schema = getWrapperCreationFormSchema(stripe_wrapper)
const result = schema.safeParse({ mode: 'schema' })
expect(result.success).toEqual(false)
// Common required field
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'wrapper_name'))
).toBeDefined()
// Schema mode specific field
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'source_schema'))
).toBeDefined()
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'target_schema'))
).toBeDefined()
})
it('should build a schema that validates wrapper specific options', () => {
const schema = getWrapperCreationFormSchema(stripe_wrapper)
const result = schema.safeParse({ mode: 'tables' })
expect(result.success).toEqual(false)
// Required option
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'api_key_id'))
).toBeDefined()
// Optional option
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'api_url'))
).toBeUndefined()
})
})
describe('getEditionFormSchema', () => {
it('should build a schema that validates wrapper specific options', () => {
const schema = getEditionFormSchema(stripe_wrapper)
const result = schema.safeParse({ mode: 'tables' })
expect(result.success).toEqual(false)
// Common required field
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'wrapper_name'))
).toBeDefined()
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'tables'))
).toBeDefined()
// Required option
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'api_key_id'))
).toBeDefined()
// Optional option
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'api_url'))
).toBeUndefined()
})
})
describe('getTableFormSchema', () => {
const table_schema = {
label: 'Accounts',
description: 'List of accounts on your Stripe account',
availableColumns: [
{
name: 'id',
type: 'text',
},
{
name: 'business_type',
type: 'text',
},
{
name: 'country',
type: 'text',
},
{
name: 'email',
type: 'text',
},
{
name: 'type',
type: 'text',
},
{
name: 'created',
type: 'timestamp',
},
{
name: 'attrs',
type: 'jsonb',
},
],
options: [
{
name: 'object',
defaultValue: 'accounts',
editable: false,
required: true,
type: 'text',
},
{
name: 'rowid_column',
label: 'Row ID Column',
defaultValue: 'id',
editable: true,
required: false,
type: 'text',
},
],
} satisfies Table
it('should build a schema that validates tables with existing schema', () => {
const schema = getTableFormSchema(table_schema)
const result = schema.safeParse({})
expect(result.success).toEqual(false)
// Common required field
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'table_name'))
).toBeDefined()
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'schema'))
).toBeDefined()
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'columns'))
).toBeDefined()
// Required options
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'object'))
).toBeDefined()
// Optional options
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'rowid_column'))
).toBeUndefined()
})
it('should build a schema that validates tables with custom schema', () => {
const schema = getTableFormSchema(table_schema)
// Because the schema_name is validated in zod superRefine, the normal validation
// must have succeeded first
const result = schema.safeParse({
table_name: 'test',
schema: 'custom',
columns: [],
object: 'acounts',
})
expect(result.success).toEqual(false)
expect(
result.error?.issues.find((issue) => issue.path.some((p) => p === 'schema_name'))
).toBeDefined()
})
})