Files
supabase/apps/studio/tests/pages/integrations/vercel/install.utils.test.ts
Saxon FletcherandDanny White 09ea558d54 Vercel install layout (#47550)
Bring the Vercel install layout up to date with other connect screens.
Resolves DEPR-615.

| Before | After |
| --- | --- |
| <img width="1600" height="1200" alt="CleanShot 2026-07-03 at 10 51
59@2x"
src="https://github.com/user-attachments/assets/6a8c2910-8c45-4c7d-8d38-8b80c5cf4c83"
/> | <img width="1150" height="1318" alt="CleanShot 2026-07-03 at 11 56
17@2x"
src="https://github.com/user-attachments/assets/3a5add5c-fea4-44f3-a368-5732257b27d9"
/> |

## Testing

- Open the deploy preview or staging URL for
`/dashboard/integrations/vercel/install` with callback params from a
real Vercel Marketplace install redirect (see _Vercel_ subheading
below).
- Confirm the install screen renders with the selected Supabase account,
organization picker, and primary install CTA.
- Remove required callback params such as `code`, `configurationId`, or
`source` to verify the "Missing Vercel installation details" warning
state.
- Clicking "Install integration" with an expired or reused `code` can
show `Creating Vercel integration failed: Failed to get Vercel access
token`; that is expected for preview UI validation. A full successful
install requires a fresh Vercel-generated code from the install flow.

To reiterate; this won’t work because the code will be invalid. But it
should show that everything is hooked up right for prod.

### Vercel

1. Go to Supabase. Open either org-level or project (settings) level
integrations.
2. Tap "[Install Vercel
Integration](https://vercel.com/integrations/supabase-local)".
3. Follow the install instructions from that Vercel page. This should
open a browser window.
4. Copy the URL of that browser window. Take the params and paste them
instead at the end of the deploy preview URL.

Example of #4:

```txt
Before:
https://supabase.com/dashboard/integrations/vercel/install?code=jDhIBDlD58zzLVtuSNjJpUSu&configurationId=icfg_v3dKllQIniSOwdVI3gypnZh3&next=https%3A%2F%2Fvercel.com%2Ftest-5706s-projects%2F~%2Fintegrations%2Ficfg_v3dKllQIniSOwdVI3gypnZh3%2Finstalled&source=marketplace&teamId=team_mPkGQZjTLBEUXh15b03iVsTg

After
https://studio-staging-git-chore-install-layout-supabase.vercel.app/dashboard/integrations/vercel/install?code=jDhIBDlD58zzLVtuSNjJpUSu&configurationId=icfg_v3dKllQIniSOwdVI3gypnZh3&next=https%3A%2F%2Fvercel.com%2Ftest-5706s-projects%2F~%2Fintegrations%2Ficfg_v3dKllQIniSOwdVI3gypnZh3%2Finstalled&source=marketplace&teamId=team_mPkGQZjTLBEUXh15b03iVsTg
```

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

## Summary by CodeRabbit

* **New Features**
* Updated the installation experience with a cleaner, more guided
layout.
* Added clearer organization selection during setup, including
visibility into which organizations are already installed.

* **Bug Fixes**
  * Improved loading and error handling during installation.
* Added clearer warnings for missing setup details, already-installed
integrations, and cases with no available organizations.
* Fixed routing behavior so organization selection is preserved more
reliably.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
2026-07-06 19:34:20 +10:00

102 lines
3.1 KiB
TypeScript

import { describe, expect, test } from 'vitest'
import {
buildVercelInstallRouteQuery,
getErrorMessage,
getVercelInstallSource,
} from '@/lib/integrations/vercel-install.utils'
describe('getErrorMessage', () => {
test('returns the message from an Error instance', () => {
expect(getErrorMessage(new Error('Something went wrong'))).toBe('Something went wrong')
})
test('returns the message from an error-like object', () => {
expect(getErrorMessage({ message: 'Request failed' })).toBe('Request failed')
})
test('returns undefined for non-string object messages', () => {
expect(getErrorMessage({ message: 404 })).toBeUndefined()
})
test('returns undefined for primitive and empty inputs', () => {
expect(getErrorMessage('Request failed')).toBeUndefined()
expect(getErrorMessage(null)).toBeUndefined()
expect(getErrorMessage(undefined)).toBeUndefined()
})
})
describe('buildVercelInstallRouteQuery', () => {
test('only keeps deploy-button destination params', () => {
expect(
buildVercelInstallRouteQuery({
source: 'deploy-button',
organizationSlug: 'acme',
currentProjectId: 'vercel-project',
externalId: 'github-repo',
next: 'https://vercel.com/callback',
configurationId: 'configuration-id',
})
).toStrictEqual({
organizationSlug: 'acme',
currentProjectId: 'vercel-project',
externalId: 'github-repo',
next: 'https://vercel.com/callback',
})
})
test('only keeps marketplace destination params', () => {
expect(
buildVercelInstallRouteQuery({
source: 'marketplace',
organizationSlug: 'acme',
configurationId: 'configuration-id',
currentProjectId: 'vercel-project',
externalId: 'github-repo',
next: 'https://vercel.com/callback',
})
).toStrictEqual({
organizationSlug: 'acme',
configurationId: 'configuration-id',
next: 'https://vercel.com/callback',
})
})
test('removes undefined params', () => {
expect(
buildVercelInstallRouteQuery({
source: 'external',
organizationSlug: 'acme',
configurationId: undefined,
next: undefined,
})
).toStrictEqual({ organizationSlug: 'acme' })
})
test('only keeps organizationSlug when source is undefined', () => {
expect(
buildVercelInstallRouteQuery({
source: undefined,
organizationSlug: 'acme',
configurationId: 'configuration-id',
currentProjectId: 'vercel-project',
externalId: 'github-repo',
next: 'https://vercel.com/callback',
})
).toStrictEqual({ organizationSlug: 'acme' })
})
})
describe('getVercelInstallSource', () => {
test('returns supported Vercel install sources', () => {
expect(getVercelInstallSource('deploy-button')).toBe('deploy-button')
expect(getVercelInstallSource('marketplace')).toBe('marketplace')
expect(getVercelInstallSource('external')).toBe('external')
})
test('returns undefined for unsupported sources', () => {
expect(getVercelInstallSource('deploybutton')).toBeUndefined()
expect(getVercelInstallSource(undefined)).toBeUndefined()
})
})