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
132 lines
4.5 KiB
TypeScript
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([])
|
|
})
|
|
})
|