Files
simstudioai--sim/apps/sim/lib/integrations/oauth-service.test.ts
T
wehub-resource-sync d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

132 lines
4.5 KiB
TypeScript

/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import integrationsJson from '@/lib/integrations/integrations.json'
import { resolveOAuthServiceForSlug } from '@/lib/integrations/oauth-service'
import type { Integration } from '@/lib/integrations/types'
const INTEGRATIONS = integrationsJson.integrations as readonly Integration[]
/**
* Pinned slug → OAuth providerId mapping for every OAuth integration in the
* catalog. Guards against silent drift between block `serviceId`s, the
* generated catalog, and `OAUTH_PROVIDERS` — the failure mode that made
* Jira Service Management, Google Slides, and Monday fall back to the
* API-key connect path.
*/
const EXPECTED_PROVIDER_BY_SLUG: Record<string, string> = {
airtable: 'airtable',
asana: 'asana',
attio: 'attio',
'azure-ad': 'microsoft-ad',
box: 'box',
'cal-com': 'calcom',
confluence: 'confluence',
docusign: 'docusign',
dropbox: 'dropbox',
gmail: 'google-email',
'google-ads': 'google-ads',
'google-bigquery': 'google-bigquery',
'google-calendar': 'google-calendar',
'google-contacts': 'google-contacts',
'google-docs': 'google-docs',
'google-drive': 'google-drive',
'google-forms': 'google-forms',
'google-groups': 'google-groups',
'google-meet': 'google-meet',
'google-sheets': 'google-sheets',
'google-slides': 'google-drive',
'google-tasks': 'google-tasks',
'google-vault': 'google-vault',
hubspot: 'hubspot',
jira: 'jira',
'jira-service-management': 'jira',
linear: 'linear',
linkedin: 'linkedin',
'microsoft-dataverse': 'microsoft-dataverse',
'microsoft-excel': 'microsoft-excel',
'microsoft-planner': 'microsoft-planner',
'microsoft-teams': 'microsoft-teams',
monday: 'monday',
notion: 'notion',
onedrive: 'onedrive',
outlook: 'outlook',
pipedrive: 'pipedrive',
reddit: 'reddit',
salesforce: 'salesforce',
sharepoint: 'sharepoint',
shopify: 'shopify',
slack: 'slack',
trello: 'trello',
wealthbox: 'wealthbox',
webflow: 'webflow',
wordpress: 'wordpress',
x: 'x',
zoom: 'zoom',
}
describe('resolveOAuthServiceForSlug', () => {
it.concurrent('resolves integrations whose name differs from the OAuth service name', () => {
const jsm = resolveOAuthServiceForSlug('jira-service-management')
expect(jsm?.providerId).toBe('jira')
expect(jsm?.serviceName).toBe('Jira')
const slides = resolveOAuthServiceForSlug('google-slides')
expect(slides?.providerId).toBe('google-drive')
const monday = resolveOAuthServiceForSlug('monday')
expect(monday?.providerId).toBe('monday')
})
it.concurrent('resolves integrations whose name matches the OAuth service name', () => {
const jira = resolveOAuthServiceForSlug('jira')
expect(jira?.providerId).toBe('jira')
expect(jira?.serviceName).toBe('Jira')
const gmail = resolveOAuthServiceForSlug('gmail')
expect(gmail?.providerId).toBe('google-email')
})
it.concurrent('returns null for unknown slugs', () => {
expect(resolveOAuthServiceForSlug('not-a-real-integration')).toBeNull()
})
it.concurrent('returns null for non-OAuth integrations', () => {
const apiKeyIntegration = INTEGRATIONS.find((entry) => entry.authType === 'api-key')
expect(apiKeyIntegration).toBeDefined()
expect(resolveOAuthServiceForSlug(apiKeyIntegration!.slug)).toBeNull()
})
it.concurrent('resolves every OAuth integration in the catalog', () => {
const oauthIntegrations = INTEGRATIONS.filter((entry) => entry.authType === 'oauth')
expect(oauthIntegrations.length).toBeGreaterThan(0)
const unresolved = oauthIntegrations
.filter((entry) => resolveOAuthServiceForSlug(entry.slug) === null)
.map((entry) => entry.slug)
expect(unresolved).toEqual([])
})
it.concurrent('resolves the pinned provider for every enumerated OAuth integration', () => {
const resolved = Object.fromEntries(
Object.keys(EXPECTED_PROVIDER_BY_SLUG).map((slug) => [
slug,
resolveOAuthServiceForSlug(slug)?.providerId ?? null,
])
)
expect(resolved).toEqual(EXPECTED_PROVIDER_BY_SLUG)
})
it.concurrent('carries oauthServiceId for exactly the OAuth catalog entries', () => {
const missing = INTEGRATIONS.filter(
(entry) => entry.authType === 'oauth' && !entry.oauthServiceId
).map((entry) => entry.slug)
const unexpected = INTEGRATIONS.filter(
(entry) => entry.authType !== 'oauth' && entry.oauthServiceId
).map((entry) => entry.slug)
expect(missing).toEqual([])
expect(unexpected).toEqual([])
})
})