Files
supabase/apps/studio/components/interfaces/ConfigDrift/ConfigurationDriftPage.utils.test.ts
Ivan Vasilov 8422045b86 chore: Use @supabase/config for the code configuration page (#50398)
How to test:
1. Connect a project to GH repo
2. Deploy the `config.toml` once
3. Change some setting in Auth
4. You should see a change in
`/dashboard/project/_/settings/code-configuration`

<img width="1271" height="1186" alt="Screenshot 2026-09-16 at 16 26 39"
src="https://github.com/user-attachments/assets/dfc135a4-e495-489e-88fd-b760383793b4"
/>

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

- **New Features**
- Configuration drift comparisons now use a consistent project
configuration schema.
- Drift details display complete current-environment and `config.toml`
values, grouped by section.
- Matching and unmanaged settings are organized into dedicated sections.
  - Configuration fields link directly to relevant Studio settings.
  - Added a warning that GitHub deployments overwrite local changes.

- **Bug Fixes**
- Configuration updates now refresh project configuration data
automatically.
  - Improved labels and formatting for boolean and redirect URL values.
- Drift errors identify invalid configuration paths and provide
corrective guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-21 16:38:37 +02:00

196 lines
5.9 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
createConfigurationDriftRows,
groupMatchedConfigFields,
groupUnmanagedConfigFields,
} from './ConfigurationDriftPage.utils'
import type {
GitHubConfigDriftField,
MatchedConfigField,
UnmanagedConfigField,
} from './github-config-drift'
const PROJECT_REF = 'abcdefgh'
function driftField(overrides: Partial<GitHubConfigDriftField>): GitHubConfigDriftField {
return {
section: 'api',
configPath: 'api.max_rows',
settingHref: (projectRef) => `/project/${projectRef}/settings/api`,
dashboardValue: 1000,
githubValue: 500,
...overrides,
}
}
function unmanagedField(overrides: Partial<UnmanagedConfigField>): UnmanagedConfigField {
return {
section: 'api',
configPath: 'api.max_rows',
dashboardValue: 1000,
...overrides,
}
}
function matchedField(overrides: Partial<MatchedConfigField>): MatchedConfigField {
return {
section: 'api',
configPath: 'api.max_rows',
value: 1000,
...overrides,
}
}
describe('createConfigurationDriftRows', () => {
it('resolves the setting href against the project ref and marks the row as drifted', () => {
const [row] = createConfigurationDriftRows([driftField({})], PROJECT_REF)
expect(row.status).toBe('drifted')
expect(row.settingHref).toBe('/project/abcdefgh/settings/api')
})
it('uses the hand-written label for a known config path', () => {
const [row] = createConfigurationDriftRows(
[driftField({ configPath: 'auth.enable_signup' })],
PROJECT_REF
)
expect(row.settingLabel).toBe('New user signups')
})
it('labels an external auth provider field as "<provider> · <key>"', () => {
const [row] = createConfigurationDriftRows(
[driftField({ configPath: 'auth.external.google.client_id' })],
PROJECT_REF
)
expect(row.settingLabel).toBe('Google client ID')
})
it('falls back to a title-cased last path segment for an unrecognized config path', () => {
const [row] = createConfigurationDriftRows(
[driftField({ configPath: 'some.unknown_setting' })],
PROJECT_REF
)
expect(row.settingLabel).toBe('Unknown Setting')
})
it('formats a missing scalar value as "Not set"', () => {
const [row] = createConfigurationDriftRows(
[driftField({ configPath: 'auth.site_url', dashboardValue: '', githubValue: undefined })],
PROJECT_REF
)
expect(row.valueDiff).toEqual({
kind: 'scalar',
dashboardValue: 'Not set',
configValue: 'Not set',
})
})
it('builds a list diff for redirect URLs, normalizing and comparing entries', () => {
const [row] = createConfigurationDriftRows(
[
driftField({
configPath: 'auth.additional_redirect_urls',
dashboardValue: ['https://a.com', 'https://b.com'],
githubValue: [' https://a.com ', 'https://c.com'],
}),
],
PROJECT_REF
)
expect(row.valueDiff).toEqual({
configValue: ' https://a.com \nhttps://c.com',
dashboardValue: 'https://a.com\nhttps://b.com',
kind: 'scalar',
})
})
})
describe('groupUnmanagedConfigFields', () => {
it('returns an empty array when there are no unmanaged fields', () => {
expect(groupUnmanagedConfigFields([])).toEqual([])
})
it('groups fields from the same section into a single group', () => {
const groups = groupUnmanagedConfigFields([
unmanagedField({ configPath: 'api.max_rows', dashboardValue: 1000 }),
unmanagedField({ configPath: 'api.enabled', dashboardValue: true }),
])
expect(groups).toHaveLength(1)
expect(groups[0]).toEqual({
section: 'api',
sectionLabel: 'API',
rows: [
{ configPath: 'api.max_rows', label: 'Max rows', value: '1000' },
{ configPath: 'api.enabled', label: 'API enabled', value: 'true' },
],
})
})
it('orders groups by CONFIG_SECTIONS order, not by input order', () => {
const groups = groupUnmanagedConfigFields([
unmanagedField({ section: 'storage', configPath: 'storage.enabled', dashboardValue: true }),
unmanagedField({ section: 'api', configPath: 'api.enabled', dashboardValue: true }),
])
expect(groups.map((group) => group.section)).toEqual(['api', 'storage'])
})
it('formats an empty-value field as "Not set"', () => {
const groups = groupUnmanagedConfigFields([
unmanagedField({ configPath: 'auth.site_url', section: 'auth', dashboardValue: undefined }),
])
expect(groups[0].rows[0].value).toBe('Not set')
})
it('joins a normalized redirect URL list with newlines', () => {
const groups = groupUnmanagedConfigFields([
unmanagedField({
section: 'auth',
configPath: 'auth.additional_redirect_urls',
dashboardValue: ['https://b.com', 'https://a.com', 'https://a.com'],
}),
])
expect(groups[0].rows[0].value).toBe('https://b.com\nhttps://a.com\nhttps://a.com')
})
})
describe('groupMatchedConfigFields', () => {
it('returns an empty array when there are no matched fields', () => {
expect(groupMatchedConfigFields([])).toEqual([])
})
it('groups fields from the same section into a single group', () => {
const groups = groupMatchedConfigFields([
matchedField({ configPath: 'api.max_rows', value: 1000 }),
matchedField({ configPath: 'api.enabled', value: true }),
])
expect(groups).toHaveLength(1)
expect(groups[0]).toEqual({
section: 'api',
sectionLabel: 'API',
rows: [
{ configPath: 'api.max_rows', label: 'Max rows', value: '1000' },
{ configPath: 'api.enabled', label: 'API enabled', value: 'true' },
],
})
})
it('orders groups by CONFIG_SECTIONS order, not by input order', () => {
const groups = groupMatchedConfigFields([
matchedField({ section: 'storage', configPath: 'storage.enabled', value: true }),
matchedField({ section: 'api', configPath: 'api.enabled', value: true }),
])
expect(groups.map((group) => group.section)).toEqual(['api', 'storage'])
})
})